From affb39fec395db863a76738ba57318b3ca0be89c Mon Sep 17 00:00:00 2001
From: linyao <602604991@qq.com>
Date: Fri, 8 Nov 2019 13:38:42 +0800
Subject: [PATCH 1/3] =?UTF-8?q?=E6=96=B0=E5=BB=BAlinyao=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E5=A4=B9=EF=BC=9B=E5=BC=80=E5=8F=91gii=E7=9A=84=E7=94=9F?=
=?UTF-8?q?=E6=88=90model=E7=9A=84=E6=A8=A1=E6=9D=BFlinyaomodel=EF=BC=9B?=
=?UTF-8?q?=E4=BF=AE=E6=94=B9environments/skeleton/kcadmin/config/main-loc?=
=?UTF-8?q?al.php=E6=96=87=E4=BB=B6=EF=BC=8C=E8=87=AA=E5=8A=A8=E7=94=9F?=
=?UTF-8?q?=E6=88=90linyaomodel=E6=A8=A1=E6=9D=BF=E6=89=80=E9=9C=80?=
=?UTF-8?q?=E7=9A=84=E7=9B=B8=E5=BA=94=E9=85=8D=E7=BD=AE=EF=BC=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
common/config/main.php | 3 +-
.../skeleton/kcadmin/config/main-local.php | 6 +
vendor/linyao/generators/model/Generator.php | 992 ++++++++++++++++++
.../linyao/generators/model/default/model.php | 117 +++
.../linyao/generators/model/default/query.php | 56 +
vendor/linyao/generators/model/form.php | 30 +
6 files changed, 1203 insertions(+), 1 deletion(-)
create mode 100644 vendor/linyao/generators/model/Generator.php
create mode 100644 vendor/linyao/generators/model/default/model.php
create mode 100644 vendor/linyao/generators/model/default/query.php
create mode 100644 vendor/linyao/generators/model/form.php
diff --git a/common/config/main.php b/common/config/main.php
index b8b2dd0..af97564 100644
--- a/common/config/main.php
+++ b/common/config/main.php
@@ -5,7 +5,8 @@ return [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
'@blobt' => '@vendor/blobt',
- '@iron' => '@vendor/iron'
+ '@iron' => '@vendor/iron',
+ '@linyao' => '@vendor/linyao'
],
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'timeZone' => 'Asia/Shanghai',
diff --git a/environments/skeleton/kcadmin/config/main-local.php b/environments/skeleton/kcadmin/config/main-local.php
index 19781e7..47cc042 100644
--- a/environments/skeleton/kcadmin/config/main-local.php
+++ b/environments/skeleton/kcadmin/config/main-local.php
@@ -26,6 +26,12 @@ if (!YII_ENV_TEST) {
'templates' => [
'blobtCrud' => '@blobt/generators/crud/default',
]
+ ],
+ 'model' => [
+ 'class' => 'linyao\generators\model\Generator',
+ 'templates' => [
+ 'linyaoModel' => '@linyao/generators/model/default',
+ ]
]
],
];
diff --git a/vendor/linyao/generators/model/Generator.php b/vendor/linyao/generators/model/Generator.php
new file mode 100644
index 0000000..fe7d4d1
--- /dev/null
+++ b/vendor/linyao/generators/model/Generator.php
@@ -0,0 +1,992 @@
+
+ * @since 2.0
+ */
+class Generator extends \yii\gii\Generator
+{
+ const RELATIONS_NONE = 'none';
+ const RELATIONS_ALL = 'all';
+ const RELATIONS_ALL_INVERSE = 'all-inverse';
+
+ public $db = 'db';
+ public $ns = 'app\models';
+ public $tableName;
+ public $modelClass;
+ public $baseClass = 'yii\db\ActiveRecord';
+ public $generateRelations = self::RELATIONS_ALL;
+ public $generateRelationsFromCurrentSchema = true;
+ public $generateLabelsFromComments = false;
+ public $useTablePrefix = false;
+ public $standardizeCapitals = false;
+ public $singularize = false;
+ public $useSchemaName = true;
+ public $generateQuery = false;
+ public $queryNs = 'app\models';
+ public $queryClass;
+ public $queryBaseClass = 'yii\db\ActiveQuery';
+
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'Model Generator';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDescription()
+ {
+ return 'This generator generates an ActiveRecord class for the specified database table.';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rules()
+ {
+ return array_merge(parent::rules(), [
+ [['db', 'ns', 'tableName', 'modelClass', 'baseClass', 'queryNs', 'queryClass', 'queryBaseClass'], 'filter', 'filter' => 'trim'],
+ [['ns', 'queryNs'], 'filter', 'filter' => function ($value) { return trim($value, '\\'); }],
+
+ [['db', 'ns', 'tableName', 'baseClass', 'queryNs', 'queryBaseClass'], 'required'],
+ [['db', 'modelClass', 'queryClass'], 'match', 'pattern' => '/^\w+$/', 'message' => 'Only word characters are allowed.'],
+ [['ns', 'baseClass', 'queryNs', 'queryBaseClass'], 'match', 'pattern' => '/^[\w\\\\]+$/', 'message' => 'Only word characters and backslashes are allowed.'],
+ [['tableName'], 'match', 'pattern' => '/^([\w ]+\.)?([\w\* ]+)$/', 'message' => 'Only word characters, and optionally spaces, an asterisk and/or a dot are allowed.'],
+ [['db'], 'validateDb'],
+ [['ns', 'queryNs'], 'validateNamespace'],
+ [['tableName'], 'validateTableName'],
+ [['modelClass'], 'validateModelClass', 'skipOnEmpty' => false],
+ [['baseClass'], 'validateClass', 'params' => ['extends' => ActiveRecord::className()]],
+ [['queryBaseClass'], 'validateClass', 'params' => ['extends' => ActiveQuery::className()]],
+ [['generateRelations'], 'in', 'range' => [self::RELATIONS_NONE, self::RELATIONS_ALL, self::RELATIONS_ALL_INVERSE]],
+ [['generateLabelsFromComments', 'useTablePrefix', 'useSchemaName', 'generateQuery', 'generateRelationsFromCurrentSchema'], 'boolean'],
+ [['enableI18N', 'standardizeCapitals', 'singularize'], 'boolean'],
+ [['messageCategory'], 'validateMessageCategory', 'skipOnEmpty' => false],
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function attributeLabels()
+ {
+ return array_merge(parent::attributeLabels(), [
+ 'ns' => 'Namespace',
+ 'db' => 'Database Connection ID',
+ 'tableName' => 'Table Name',
+ 'standardizeCapitals' => 'Standardize Capitals',
+ 'singularize' => 'Singularize',
+ 'modelClass' => 'Model Class Name',
+ 'baseClass' => 'Base Class',
+ 'generateRelations' => 'Generate Relations',
+ 'generateRelationsFromCurrentSchema' => 'Generate Relations from Current Schema',
+ 'generateLabelsFromComments' => 'Generate Labels from DB Comments',
+ 'generateQuery' => 'Generate ActiveQuery',
+ 'queryNs' => 'ActiveQuery Namespace',
+ 'queryClass' => 'ActiveQuery Class',
+ 'queryBaseClass' => 'ActiveQuery Base Class',
+ 'useSchemaName' => 'Use Schema Name',
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hints()
+ {
+ return array_merge(parent::hints(), [
+ 'ns' => 'This is the namespace of the ActiveRecord class to be generated, e.g., app\models
',
+ 'db' => 'This is the ID of the DB application component.',
+ 'tableName' => 'This is the name of the DB table that the new ActiveRecord class is associated with, e.g. post
.
+ The table name may consist of the DB schema part if needed, e.g. public.post
.
+ The table name may end with asterisk to match multiple table names, e.g. tbl_*
+ will match tables who name starts with tbl_
. In this case, multiple ActiveRecord classes
+ will be generated, one for each matching table name; and the class names will be generated from
+ the matching characters. For example, table tbl_post
will generate Post
+ class.',
+ 'modelClass' => 'This is the name of the ActiveRecord class to be generated. The class name should not contain
+ the namespace part as it is specified in "Namespace". You do not need to specify the class name
+ if "Table Name" ends with asterisk, in which case multiple ActiveRecord classes will be generated.',
+ 'standardizeCapitals' => 'This indicates whether the generated class names should have standardized capitals. For example,
+ table names like SOME_TABLE
or Other_Table
will have class names SomeTable
+ and OtherTable
, respectively. If not checked, the same tables will have class names SOMETABLE
+ and OtherTable
instead.',
+ 'singularize' => 'This indicates whether the generated class names should be singularized. For example,
+ table names like some_tables
will have class names SomeTable
.',
+ 'baseClass' => 'This is the base class of the new ActiveRecord class. It should be a fully qualified namespaced class name.',
+ 'generateRelations' => 'This indicates whether the generator should generate relations based on
+ foreign key constraints it detects in the database. Note that if your database contains too many tables,
+ you may want to uncheck this option to accelerate the code generation process.',
+ 'generateRelationsFromCurrentSchema' => 'This indicates whether the generator should generate relations from current schema or from all available schemas.',
+ 'generateLabelsFromComments' => 'This indicates whether the generator should generate attribute labels
+ by using the comments of the corresponding DB columns.',
+ 'useTablePrefix' => 'This indicates whether the table name returned by the generated ActiveRecord class
+ should consider the tablePrefix
setting of the DB connection. For example, if the
+ table name is tbl_post
and tablePrefix=tbl_
, the ActiveRecord class
+ will return the table name as {{%post}}
.',
+ 'useSchemaName' => 'This indicates whether to include the schema name in the ActiveRecord class
+ when it\'s auto generated. Only non default schema would be used.',
+ 'generateQuery' => 'This indicates whether to generate ActiveQuery for the ActiveRecord class.',
+ 'queryNs' => 'This is the namespace of the ActiveQuery class to be generated, e.g., app\models
',
+ 'queryClass' => 'This is the name of the ActiveQuery class to be generated. The class name should not contain
+ the namespace part as it is specified in "ActiveQuery Namespace". You do not need to specify the class name
+ if "Table Name" ends with asterisk, in which case multiple ActiveQuery classes will be generated.',
+ 'queryBaseClass' => 'This is the base class of the new ActiveQuery class. It should be a fully qualified namespaced class name.',
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function autoCompleteData()
+ {
+ $db = $this->getDbConnection();
+ if ($db !== null) {
+ return [
+ 'tableName' => function () use ($db) {
+ return $db->getSchema()->getTableNames();
+ },
+ ];
+ }
+
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function requiredTemplates()
+ {
+ // @todo make 'query.php' to be required before 2.1 release
+ return ['model.php'/*, 'query.php'*/];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function stickyAttributes()
+ {
+ return array_merge(parent::stickyAttributes(), ['ns', 'db', 'baseClass', 'generateRelations', 'generateLabelsFromComments', 'queryNs', 'queryBaseClass', 'useTablePrefix', 'generateQuery']);
+ }
+
+ /**
+ * Returns the `tablePrefix` property of the DB connection as specified
+ *
+ * @return string
+ * @since 2.0.5
+ * @see getDbConnection
+ */
+ public function getTablePrefix()
+ {
+ $db = $this->getDbConnection();
+ if ($db !== null) {
+ return $db->tablePrefix;
+ }
+
+ return '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function generate()
+ {
+ $files = [];
+ $relations = $this->generateRelations();
+ $db = $this->getDbConnection();
+ foreach ($this->getTableNames() as $tableName) {
+ // model :
+ $modelClassName = $this->generateClassName($tableName);
+ $queryClassName = ($this->generateQuery) ? $this->generateQueryClassName($modelClassName) : false;
+ $tableSchema = $db->getTableSchema($tableName);
+ $params = [
+ 'tableName' => $tableName,
+ 'className' => $modelClassName,
+ 'queryClassName' => $queryClassName,
+ 'tableSchema' => $tableSchema,
+ 'properties' => $this->generateProperties($tableSchema),
+ 'labels' => $this->generateLabels($tableSchema),
+ 'rules' => $this->generateRules($tableSchema),
+ 'relations' => isset($relations[$tableName]) ? $relations[$tableName] : [],
+ ];
+ $files[] = new CodeFile(
+ Yii::getAlias('@' . str_replace('\\', '/', $this->ns)) . '/' . $modelClassName . '.php',
+ $this->render('model.php', $params)
+ );
+
+ // query :
+ if ($queryClassName) {
+ $params['className'] = $queryClassName;
+ $params['modelClassName'] = $modelClassName;
+ $files[] = new CodeFile(
+ Yii::getAlias('@' . str_replace('\\', '/', $this->queryNs)) . '/' . $queryClassName . '.php',
+ $this->render('query.php', $params)
+ );
+ }
+ }
+
+ return $files;
+ }
+
+ /**
+ * Generates the properties for the specified table.
+ * @param \yii\db\TableSchema $table the table schema
+ * @return array the generated properties (property => type)
+ * @since 2.0.6
+ */
+ protected function generateProperties($table)
+ {
+ $properties = [];
+ foreach ($table->columns as $column) {
+ $columnPhpType = $column->phpType;
+ if ($columnPhpType === 'integer') {
+ $type = 'int';
+ } elseif ($columnPhpType === 'boolean') {
+ $type = 'bool';
+ } else {
+ $type = $columnPhpType;
+ }
+ $properties[$column->name] = [
+ 'type' => $type,
+ 'name' => $column->name,
+ 'comment' => $column->comment,
+ ];
+ }
+
+ return $properties;
+ }
+
+ /**
+ * Generates the attribute labels for the specified table.
+ * @param \yii\db\TableSchema $table the table schema
+ * @return array the generated attribute labels (name => label)
+ */
+ public function generateLabels($table)
+ {
+// $labels = [];
+// foreach ($table->columns as $column) {
+// if ($this->generateLabelsFromComments && !empty($column->comment)) {
+// $labels[$column->name] = $column->comment;
+// } elseif (!strcasecmp($column->name, 'id')) {
+// $labels[$column->name] = 'ID';
+// } else {
+// $label = Inflector::camel2words($column->name);
+// if (!empty($label) && substr_compare($label, ' id', -3, 3, true) === 0) {
+// $label = substr($label, 0, -3) . ' ID';
+// }
+// $labels[$column->name] = $label;
+// }
+// }
+//
+// return $labels;
+
+ $labels=array();
+
+ $sql ="SELECT COLUMN_NAME, COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '$table->name'";
+
+ $res = Yii::$app->getDb()->createCommand($sql)->query();
+
+ foreach ($res as $column){
+
+ if (!empty($column['COLUMN_COMMENT']))
+
+ $labels[$column['COLUMN_NAME']]= $column['COLUMN_COMMENT'];
+
+ else
+
+ $labels[$column['COLUMN_NAME']]= $column['COLUMN_NAME'];
+
+ }
+
+ return $labels;
+ }
+
+ /**
+ * Generates validation rules for the specified table.
+ * @param \yii\db\TableSchema $table the table schema
+ * @return array the generated validation rules
+ */
+ public function generateRules($table)
+ {
+ $types = [];
+ $lengths = [];
+ foreach ($table->columns as $column) {
+ if ($column->autoIncrement) {
+ continue;
+ }
+ if (!$column->allowNull && $column->defaultValue === null) {
+ $types['required'][] = $column->name;
+ }
+ switch ($column->type) {
+ case Schema::TYPE_SMALLINT:
+ case Schema::TYPE_INTEGER:
+ case Schema::TYPE_BIGINT:
+ case Schema::TYPE_TINYINT:
+ $types['integer'][] = $column->name;
+ break;
+ case Schema::TYPE_BOOLEAN:
+ $types['boolean'][] = $column->name;
+ break;
+ case Schema::TYPE_FLOAT:
+ case Schema::TYPE_DOUBLE:
+ case Schema::TYPE_DECIMAL:
+ case Schema::TYPE_MONEY:
+ $types['number'][] = $column->name;
+ break;
+ case Schema::TYPE_DATE:
+ case Schema::TYPE_TIME:
+ case Schema::TYPE_DATETIME:
+ case Schema::TYPE_TIMESTAMP:
+ case Schema::TYPE_JSON:
+ $types['safe'][] = $column->name;
+ break;
+ default: // strings
+ if ($column->size > 0) {
+ $lengths[$column->size][] = $column->name;
+ } else {
+ $types['string'][] = $column->name;
+ }
+ }
+ }
+ $rules = [];
+ $driverName = $this->getDbDriverName();
+ foreach ($types as $type => $columns) {
+ if ($driverName === 'pgsql' && $type === 'integer') {
+ $rules[] = "[['" . implode("', '", $columns) . "'], 'default', 'value' => null]";
+ }
+ $rules[] = "[['" . implode("', '", $columns) . "'], '$type']";
+ }
+ foreach ($lengths as $length => $columns) {
+ $rules[] = "[['" . implode("', '", $columns) . "'], 'string', 'max' => $length]";
+ }
+
+ $db = $this->getDbConnection();
+
+ // Unique indexes rules
+ try {
+ $uniqueIndexes = array_merge($db->getSchema()->findUniqueIndexes($table), [$table->primaryKey]);
+ $uniqueIndexes = array_unique($uniqueIndexes, SORT_REGULAR);
+ foreach ($uniqueIndexes as $uniqueColumns) {
+ // Avoid validating auto incremental columns
+ if (!$this->isColumnAutoIncremental($table, $uniqueColumns)) {
+ $attributesCount = count($uniqueColumns);
+
+ if ($attributesCount === 1) {
+ $rules[] = "[['" . $uniqueColumns[0] . "'], 'unique']";
+ } elseif ($attributesCount > 1) {
+ $columnsList = implode("', '", $uniqueColumns);
+ $rules[] = "[['$columnsList'], 'unique', 'targetAttribute' => ['$columnsList']]";
+ }
+ }
+ }
+ } catch (NotSupportedException $e) {
+ // doesn't support unique indexes information...do nothing
+ }
+
+ // Exist rules for foreign keys
+ foreach ($table->foreignKeys as $refs) {
+ $refTable = $refs[0];
+ $refTableSchema = $db->getTableSchema($refTable);
+ if ($refTableSchema === null) {
+ // Foreign key could point to non-existing table: https://github.com/yiisoft/yii2-gii/issues/34
+ continue;
+ }
+ $refClassName = $this->generateClassName($refTable);
+ unset($refs[0]);
+ $attributes = implode("', '", array_keys($refs));
+ $targetAttributes = [];
+ foreach ($refs as $key => $value) {
+ $targetAttributes[] = "'$key' => '$value'";
+ }
+ $targetAttributes = implode(', ', $targetAttributes);
+ $rules[] = "[['$attributes'], 'exist', 'skipOnError' => true, 'targetClass' => $refClassName::className(), 'targetAttribute' => [$targetAttributes]]";
+ }
+
+ return $rules;
+ }
+
+ /**
+ * Generates relations using a junction table by adding an extra viaTable().
+ * @param \yii\db\TableSchema the table being checked
+ * @param array $fks obtained from the checkJunctionTable() method
+ * @param array $relations
+ * @return array modified $relations
+ */
+ private function generateManyManyRelations($table, $fks, $relations)
+ {
+ $db = $this->getDbConnection();
+
+ foreach ($fks as $pair) {
+ list($firstKey, $secondKey) = $pair;
+ $table0 = $firstKey[0];
+ $table1 = $secondKey[0];
+ unset($firstKey[0], $secondKey[0]);
+ $className0 = $this->generateClassName($table0);
+ $className1 = $this->generateClassName($table1);
+ $table0Schema = $db->getTableSchema($table0);
+ $table1Schema = $db->getTableSchema($table1);
+
+ // @see https://github.com/yiisoft/yii2-gii/issues/166
+ if ($table0Schema === null || $table1Schema === null) {
+ continue;
+ }
+
+ $link = $this->generateRelationLink(array_flip($secondKey));
+ $viaLink = $this->generateRelationLink($firstKey);
+ $relationName = $this->generateRelationName($relations, $table0Schema, key($secondKey), true);
+ $relations[$table0Schema->fullName][$relationName] = [
+ "return \$this->hasMany($className1::className(), $link)->viaTable('"
+ . $this->generateTableName($table->name) . "', $viaLink);",
+ $className1,
+ true,
+ ];
+
+ $link = $this->generateRelationLink(array_flip($firstKey));
+ $viaLink = $this->generateRelationLink($secondKey);
+ $relationName = $this->generateRelationName($relations, $table1Schema, key($firstKey), true);
+ $relations[$table1Schema->fullName][$relationName] = [
+ "return \$this->hasMany($className0::className(), $link)->viaTable('"
+ . $this->generateTableName($table->name) . "', $viaLink);",
+ $className0,
+ true,
+ ];
+ }
+
+ return $relations;
+ }
+
+ /**
+ * @return string[] all db schema names or an array with a single empty string
+ * @throws NotSupportedException
+ * @since 2.0.5
+ */
+ protected function getSchemaNames()
+ {
+ $db = $this->getDbConnection();
+
+ if ($this->generateRelationsFromCurrentSchema) {
+ if ($db->schema->defaultSchema !== null) {
+ return [$db->schema->defaultSchema];
+ }
+ return [''];
+ }
+
+ $schema = $db->getSchema();
+ if ($schema->hasMethod('getSchemaNames')) { // keep BC to Yii versions < 2.0.4
+ try {
+ $schemaNames = $schema->getSchemaNames();
+ } catch (NotSupportedException $e) {
+ // schema names are not supported by schema
+ }
+ }
+ if (!isset($schemaNames)) {
+ if (($pos = strpos($this->tableName, '.')) !== false) {
+ $schemaNames = [substr($this->tableName, 0, $pos)];
+ } else {
+ $schemaNames = [''];
+ }
+ }
+ return $schemaNames;
+ }
+
+ /**
+ * @return array the generated relation declarations
+ */
+ protected function generateRelations()
+ {
+ if ($this->generateRelations === self::RELATIONS_NONE) {
+ return [];
+ }
+
+ $db = $this->getDbConnection();
+ $relations = [];
+ $schemaNames = $this->getSchemaNames();
+ foreach ($schemaNames as $schemaName) {
+ foreach ($db->getSchema()->getTableSchemas($schemaName) as $table) {
+ $className = $this->generateClassName($table->fullName);
+ foreach ($table->foreignKeys as $refs) {
+ $refTable = $refs[0];
+ $refTableSchema = $db->getTableSchema($refTable);
+ if ($refTableSchema === null) {
+ // Foreign key could point to non-existing table: https://github.com/yiisoft/yii2-gii/issues/34
+ continue;
+ }
+ unset($refs[0]);
+ $fks = array_keys($refs);
+ $refClassName = $this->generateClassName($refTable);
+
+ // Add relation for this table
+ $link = $this->generateRelationLink(array_flip($refs));
+ $relationName = $this->generateRelationName($relations, $table, $fks[0], false);
+ $relations[$table->fullName][$relationName] = [
+ "return \$this->hasOne($refClassName::className(), $link);",
+ $refClassName,
+ false,
+ ];
+
+ // Add relation for the referenced table
+ $hasMany = $this->isHasManyRelation($table, $fks);
+ $link = $this->generateRelationLink($refs);
+ $relationName = $this->generateRelationName($relations, $refTableSchema, $className, $hasMany);
+ $relations[$refTableSchema->fullName][$relationName] = [
+ "return \$this->" . ($hasMany ? 'hasMany' : 'hasOne') . "($className::className(), $link);",
+ $className,
+ $hasMany,
+ ];
+ }
+
+ if (($junctionFks = $this->checkJunctionTable($table)) === false) {
+ continue;
+ }
+
+ $relations = $this->generateManyManyRelations($table, $junctionFks, $relations);
+ }
+ }
+
+ if ($this->generateRelations === self::RELATIONS_ALL_INVERSE) {
+ return $this->addInverseRelations($relations);
+ }
+
+ return $relations;
+ }
+
+ /**
+ * Adds inverse relations
+ *
+ * @param array $relations relation declarations
+ * @return array relation declarations extended with inverse relation names
+ * @since 2.0.5
+ */
+ protected function addInverseRelations($relations)
+ {
+ $db = $this->getDbConnection();
+ $relationNames = [];
+
+ $schemaNames = $this->getSchemaNames();
+ foreach ($schemaNames as $schemaName) {
+ foreach ($db->schema->getTableSchemas($schemaName) as $table) {
+ $className = $this->generateClassName($table->fullName);
+ foreach ($table->foreignKeys as $refs) {
+ $refTable = $refs[0];
+ $refTableSchema = $db->getTableSchema($refTable);
+ if ($refTableSchema === null) {
+ // Foreign key could point to non-existing table: https://github.com/yiisoft/yii2-gii/issues/34
+ continue;
+ }
+ unset($refs[0]);
+ $fks = array_keys($refs);
+
+ $leftRelationName = $this->generateRelationName($relationNames, $table, $fks[0], false);
+ $relationNames[$table->fullName][$leftRelationName] = true;
+ $hasMany = $this->isHasManyRelation($table, $fks);
+ $rightRelationName = $this->generateRelationName(
+ $relationNames,
+ $refTableSchema,
+ $className,
+ $hasMany
+ );
+ $relationNames[$refTableSchema->fullName][$rightRelationName] = true;
+
+ $relations[$table->fullName][$leftRelationName][0] =
+ rtrim($relations[$table->fullName][$leftRelationName][0], ';')
+ . "->inverseOf('".lcfirst($rightRelationName)."');";
+ $relations[$refTableSchema->fullName][$rightRelationName][0] =
+ rtrim($relations[$refTableSchema->fullName][$rightRelationName][0], ';')
+ . "->inverseOf('".lcfirst($leftRelationName)."');";
+ }
+ }
+ }
+ return $relations;
+ }
+
+ /**
+ * Determines if relation is of has many type
+ *
+ * @param TableSchema $table
+ * @param array $fks
+ * @return bool
+ * @since 2.0.5
+ */
+ protected function isHasManyRelation($table, $fks)
+ {
+ $uniqueKeys = [$table->primaryKey];
+ try {
+ $uniqueKeys = array_merge($uniqueKeys, $this->getDbConnection()->getSchema()->findUniqueIndexes($table));
+ } catch (NotSupportedException $e) {
+ // ignore
+ }
+ foreach ($uniqueKeys as $uniqueKey) {
+ if (count(array_diff(array_merge($uniqueKey, $fks), array_intersect($uniqueKey, $fks))) === 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Generates the link parameter to be used in generating the relation declaration.
+ * @param array $refs reference constraint
+ * @return string the generated link parameter.
+ */
+ protected function generateRelationLink($refs)
+ {
+ $pairs = [];
+ foreach ($refs as $a => $b) {
+ $pairs[] = "'$a' => '$b'";
+ }
+
+ return '[' . implode(', ', $pairs) . ']';
+ }
+
+ /**
+ * Checks if the given table is a junction table, that is it has at least one pair of unique foreign keys.
+ * @param \yii\db\TableSchema the table being checked
+ * @return array|bool all unique foreign key pairs if the table is a junction table,
+ * or false if the table is not a junction table.
+ */
+ protected function checkJunctionTable($table)
+ {
+ if (count($table->foreignKeys) < 2) {
+ return false;
+ }
+ $uniqueKeys = [$table->primaryKey];
+ try {
+ $uniqueKeys = array_merge($uniqueKeys, $this->getDbConnection()->getSchema()->findUniqueIndexes($table));
+ } catch (NotSupportedException $e) {
+ // ignore
+ }
+ $result = [];
+ // find all foreign key pairs that have all columns in an unique constraint
+ $foreignKeys = array_values($table->foreignKeys);
+ $foreignKeysCount = count($foreignKeys);
+
+ for ($i = 0; $i < $foreignKeysCount; $i++) {
+ $firstColumns = $foreignKeys[$i];
+ unset($firstColumns[0]);
+
+ for ($j = $i + 1; $j < $foreignKeysCount; $j++) {
+ $secondColumns = $foreignKeys[$j];
+ unset($secondColumns[0]);
+
+ $fks = array_merge(array_keys($firstColumns), array_keys($secondColumns));
+ foreach ($uniqueKeys as $uniqueKey) {
+ if (count(array_diff(array_merge($uniqueKey, $fks), array_intersect($uniqueKey, $fks))) === 0) {
+ // save the foreign key pair
+ $result[] = [$foreignKeys[$i], $foreignKeys[$j]];
+ break;
+ }
+ }
+ }
+ }
+ return empty($result) ? false : $result;
+ }
+
+ /**
+ * Generate a relation name for the specified table and a base name.
+ * @param array $relations the relations being generated currently.
+ * @param \yii\db\TableSchema $table the table schema
+ * @param string $key a base name that the relation name may be generated from
+ * @param bool $multiple whether this is a has-many relation
+ * @return string the relation name
+ */
+ protected function generateRelationName($relations, $table, $key, $multiple)
+ {
+ static $baseModel;
+ /* @var $baseModel \yii\db\ActiveRecord */
+ if ($baseModel === null) {
+ $baseClass = $this->baseClass;
+ $baseClassReflector = new \ReflectionClass($baseClass);
+ if ($baseClassReflector->isAbstract()) {
+ $baseClassWrapper =
+ 'namespace ' . __NAMESPACE__ . ';'.
+ 'class GiiBaseClassWrapper extends \\' . $baseClass . ' {' .
+ 'public static function tableName(){' .
+ 'return "' . addslashes($table->fullName) . '";' .
+ '}' .
+ '};' .
+ 'return new GiiBaseClassWrapper();';
+ $baseModel = eval($baseClassWrapper);
+ } else {
+ $baseModel = new $baseClass();
+ }
+ $baseModel->setAttributes([]);
+ }
+
+ if (!empty($key) && strcasecmp($key, 'id')) {
+ if (substr_compare($key, 'id', -2, 2, true) === 0) {
+ $key = rtrim(substr($key, 0, -2), '_');
+ } elseif (substr_compare($key, 'id', 0, 2, true) === 0) {
+ $key = ltrim(substr($key, 2, strlen($key)), '_');
+ }
+ }
+ if ($multiple) {
+ $key = Inflector::pluralize($key);
+ }
+ $name = $rawName = Inflector::id2camel($key, '_');
+ $i = 0;
+ while ($baseModel->hasProperty(lcfirst($name))) {
+ $name = $rawName . ($i++);
+ }
+ while (isset($table->columns[lcfirst($name)])) {
+ $name = $rawName . ($i++);
+ }
+ while (isset($relations[$table->fullName][$name])) {
+ $name = $rawName . ($i++);
+ }
+
+ return $name;
+ }
+
+ /**
+ * Validates the [[db]] attribute.
+ */
+ public function validateDb()
+ {
+ if (!Yii::$app->has($this->db)) {
+ $this->addError('db', 'There is no application component named "db".');
+ } elseif (!Yii::$app->get($this->db) instanceof Connection) {
+ $this->addError('db', 'The "db" application component must be a DB connection instance.');
+ }
+ }
+
+ /**
+ * Validates the namespace.
+ *
+ * @param string $attribute Namespace variable.
+ */
+ public function validateNamespace($attribute)
+ {
+ $value = $this->$attribute;
+ $value = ltrim($value, '\\');
+ $path = Yii::getAlias('@' . str_replace('\\', '/', $value), false);
+ if ($path === false) {
+ $this->addError($attribute, 'Namespace must be associated with an existing directory.');
+ }
+ }
+
+ /**
+ * Validates the [[modelClass]] attribute.
+ */
+ public function validateModelClass()
+ {
+ if ($this->isReservedKeyword($this->modelClass)) {
+ $this->addError('modelClass', 'Class name cannot be a reserved PHP keyword.');
+ }
+ if ((empty($this->tableName) || substr_compare($this->tableName, '*', -1, 1)) && $this->modelClass == '') {
+ $this->addError('modelClass', 'Model Class cannot be blank if table name does not end with asterisk.');
+ }
+ }
+
+ /**
+ * Validates the [[tableName]] attribute.
+ */
+ public function validateTableName()
+ {
+ if (strpos($this->tableName, '*') !== false && substr_compare($this->tableName, '*', -1, 1)) {
+ $this->addError('tableName', 'Asterisk is only allowed as the last character.');
+
+ return;
+ }
+ $tables = $this->getTableNames();
+ if (empty($tables)) {
+ $this->addError('tableName', "Table '{$this->tableName}' does not exist.");
+ } else {
+ foreach ($tables as $table) {
+ $class = $this->generateClassName($table);
+ if ($this->isReservedKeyword($class)) {
+ $this->addError('tableName', "Table '$table' will generate a class which is a reserved PHP keyword.");
+ break;
+ }
+ }
+ }
+ }
+
+ protected $tableNames;
+ protected $classNames;
+
+ /**
+ * @return array the table names that match the pattern specified by [[tableName]].
+ */
+ protected function getTableNames()
+ {
+ if ($this->tableNames !== null) {
+ return $this->tableNames;
+ }
+ $db = $this->getDbConnection();
+ if ($db === null) {
+ return [];
+ }
+ $tableNames = [];
+ if (strpos($this->tableName, '*') !== false) {
+ if (($pos = strrpos($this->tableName, '.')) !== false) {
+ $schema = substr($this->tableName, 0, $pos);
+ $pattern = '/^' . str_replace('*', '\w+', substr($this->tableName, $pos + 1)) . '$/';
+ } else {
+ $schema = '';
+ $pattern = '/^' . str_replace('*', '\w+', $this->tableName) . '$/';
+ }
+
+ foreach ($db->schema->getTableNames($schema) as $table) {
+ if (preg_match($pattern, $table)) {
+ $tableNames[] = $schema === '' ? $table : ($schema . '.' . $table);
+ }
+ }
+ } elseif (($table = $db->getTableSchema($this->tableName, true)) !== null) {
+ $tableNames[] = $this->tableName;
+ $this->classNames[$this->tableName] = $this->modelClass;
+ }
+
+ return $this->tableNames = $tableNames;
+ }
+
+ /**
+ * Generates the table name by considering table prefix.
+ * If [[useTablePrefix]] is false, the table name will be returned without change.
+ * @param string $tableName the table name (which may contain schema prefix)
+ * @return string the generated table name
+ */
+ public function generateTableName($tableName)
+ {
+ if (!$this->useTablePrefix) {
+ return $tableName;
+ }
+
+ $db = $this->getDbConnection();
+ if (preg_match("/^{$db->tablePrefix}(.*?)$/", $tableName, $matches)) {
+ $tableName = '{{%' . $matches[1] . '}}';
+ } elseif (preg_match("/^(.*?){$db->tablePrefix}$/", $tableName, $matches)) {
+ $tableName = '{{' . $matches[1] . '%}}';
+ }
+ return $tableName;
+ }
+
+ /**
+ * Generates a class name from the specified table name.
+ * @param string $tableName the table name (which may contain schema prefix)
+ * @param bool $useSchemaName should schema name be included in the class name, if present
+ * @return string the generated class name
+ */
+ protected function generateClassName($tableName, $useSchemaName = null)
+ {
+ if (isset($this->classNames[$tableName])) {
+ return $this->classNames[$tableName];
+ }
+
+ $schemaName = '';
+ $fullTableName = $tableName;
+ if (($pos = strrpos($tableName, '.')) !== false) {
+ if (($useSchemaName === null && $this->useSchemaName) || $useSchemaName) {
+ $schemaName = substr($tableName, 0, $pos) . '_';
+ }
+ $tableName = substr($tableName, $pos + 1);
+ }
+
+ $db = $this->getDbConnection();
+ $patterns = [];
+ $patterns[] = "/^{$db->tablePrefix}(.*?)$/";
+ $patterns[] = "/^(.*?){$db->tablePrefix}$/";
+ if (strpos($this->tableName, '*') !== false) {
+ $pattern = $this->tableName;
+ if (($pos = strrpos($pattern, '.')) !== false) {
+ $pattern = substr($pattern, $pos + 1);
+ }
+ $patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/';
+ }
+ $className = $tableName;
+ foreach ($patterns as $pattern) {
+ if (preg_match($pattern, $tableName, $matches)) {
+ $className = $matches[1];
+ break;
+ }
+ }
+
+ if ($this->standardizeCapitals) {
+ $schemaName = ctype_upper(preg_replace('/[_-]/', '', $schemaName)) ? strtolower($schemaName) : $schemaName;
+ $className = ctype_upper(preg_replace('/[_-]/', '', $className)) ? strtolower($className) : $className;
+ $this->classNames[$fullTableName] = Inflector::camelize(Inflector::camel2words($schemaName.$className));
+ } else {
+ $this->classNames[$fullTableName] = Inflector::id2camel($schemaName.$className, '_');
+ }
+
+ if ($this->singularize) {
+ $this->classNames[$fullTableName] = Inflector::singularize($this->classNames[$fullTableName]);
+ }
+
+ return $this->classNames[$fullTableName];
+ }
+
+ /**
+ * Generates a query class name from the specified model class name.
+ * @param string $modelClassName model class name
+ * @return string generated class name
+ */
+ protected function generateQueryClassName($modelClassName)
+ {
+ $queryClassName = $this->queryClass;
+ if (empty($queryClassName) || strpos($this->tableName, '*') !== false) {
+ $queryClassName = $modelClassName . 'Query';
+ }
+ return $queryClassName;
+ }
+
+ /**
+ * @return Connection the DB connection as specified by [[db]].
+ */
+ protected function getDbConnection()
+ {
+ return Yii::$app->get($this->db, false);
+ }
+
+ /**
+ * @return string|null driver name of db connection.
+ * In case db is not instance of \yii\db\Connection null will be returned.
+ * @since 2.0.6
+ */
+ protected function getDbDriverName()
+ {
+ /** @var Connection $db */
+ $db = $this->getDbConnection();
+ return $db instanceof \yii\db\Connection ? $db->driverName : null;
+ }
+
+ /**
+ * Checks if any of the specified columns is auto incremental.
+ * @param \yii\db\TableSchema $table the table schema
+ * @param array $columns columns to check for autoIncrement property
+ * @return bool whether any of the specified columns is auto incremental.
+ */
+ protected function isColumnAutoIncremental($table, $columns)
+ {
+ foreach ($columns as $column) {
+ if (isset($table->columns[$column]) && $table->columns[$column]->autoIncrement) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/linyao/generators/model/default/model.php b/vendor/linyao/generators/model/default/model.php
new file mode 100644
index 0000000..99d57e7
--- /dev/null
+++ b/vendor/linyao/generators/model/default/model.php
@@ -0,0 +1,117 @@
+ [type, name. comment]) */
+/* @var $labels string[] list of attribute labels (name => label) */
+/* @var $rules string[] list of validation rules */
+/* @var $relations array list of relations (name => relation declaration) */
+
+echo "
+
+namespace = $generator->ns ?>;
+
+use Yii;
+use yii\behaviors\TimestampBehavior;
+
+/**
+ * This is the model class for table "= $generator->generateTableName($tableName) ?>".
+ *
+ $data): ?>
+ * @property = "{$data['type']} \${$property}" . ($data['comment'] ? ' ' . strtr($data['comment'], ["\n" => ' ']) : '') . "\n" ?>
+
+
+ *
+ $relation): ?>
+ * @property = $relation[1] . ($relation[2] ? '[]' : '') . ' $' . lcfirst($name) . "\n" ?>
+
+
+ */
+class = $className ?> extends = '\\' . ltrim($generator->baseClass, '\\') . "\n" ?>
+{
+ /**
+ * {@inheritdoc}
+ */
+ public static function tableName()
+ {
+ return '= $generator->generateTableName($tableName) ?>';
+ }
+db !== 'db'): ?>
+
+ /**
+ * @return \yii\db\Connection the database connection used by this AR class.
+ */
+ public static function getDb()
+ {
+ return Yii::$app->get('= $generator->db ?>');
+ }
+
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rules()
+ {
+ return [= empty($rules) ? '' : ("\n " . implode(",\n ", $rules) . ",\n ") ?>];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function attributeLabels()
+ {
+ return [
+ $label): ?>
+ = "'$name' => " . $generator->generateString($label) . ",\n" ?>
+
+ ];
+ }
+ $relation): ?>
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function get= $name ?>()
+ {
+ = $relation[0] . "\n" ?>
+ }
+
+
+ns === $generator->queryNs) ? $queryClassName : '\\' . $generator->queryNs . '\\' . $queryClassName;
+ echo "\n";
+?>
+ /**
+ * {@inheritdoc}
+ * @return = $queryClassFullName ?> the active query used by this AR class.
+ */
+ public static function find()
+ {
+ return new = $queryClassFullName ?>(get_called_class());
+ }
+
+
+
+ public function behaviors()
+ {
+ return [
+ [
+ 'class' => TimestampBehavior::className(),
+ 'createdAtAttribute' => 'created_at',
+ 'updatedAtAttribute' => 'updated_at',
+ 'value' => function() {
+ return time();
+ },
+ ],
+ ];
+ }
+
+}
diff --git a/vendor/linyao/generators/model/default/query.php b/vendor/linyao/generators/model/default/query.php
new file mode 100644
index 0000000..c362dfe
--- /dev/null
+++ b/vendor/linyao/generators/model/default/query.php
@@ -0,0 +1,56 @@
+ label) */
+/* @var $rules string[] list of validation rules */
+/* @var $relations array list of relations (name => relation declaration) */
+/* @var $className string class name */
+/* @var $modelClassName string related model class name */
+
+$modelFullClassName = $modelClassName;
+if ($generator->ns !== $generator->queryNs) {
+ $modelFullClassName = '\\' . $generator->ns . '\\' . $modelFullClassName;
+}
+
+echo "
+
+namespace = $generator->queryNs ?>;
+
+/**
+ * This is the ActiveQuery class for [[= $modelFullClassName ?>]].
+ *
+ * @see = $modelFullClassName . "\n" ?>
+ */
+class = $className ?> extends = '\\' . ltrim($generator->queryBaseClass, '\\') . "\n" ?>
+{
+ /*public function active()
+ {
+ return $this->andWhere('[[status]]=1');
+ }*/
+
+ /**
+ * {@inheritdoc}
+ * @return = $modelFullClassName ?>[]|array
+ */
+ public function all($db = null)
+ {
+ return parent::all($db);
+ }
+
+ /**
+ * {@inheritdoc}
+ * @return = $modelFullClassName ?>|array|null
+ */
+ public function one($db = null)
+ {
+ return parent::one($db);
+ }
+}
diff --git a/vendor/linyao/generators/model/form.php b/vendor/linyao/generators/model/form.php
new file mode 100644
index 0000000..2fa118f
--- /dev/null
+++ b/vendor/linyao/generators/model/form.php
@@ -0,0 +1,30 @@
+field($generator, 'tableName')->textInput(['table_prefix' => $generator->getTablePrefix()]);
+echo $form->field($generator, 'modelClass');
+echo $form->field($generator, 'standardizeCapitals')->checkbox();
+echo $form->field($generator, 'singularize')->checkbox();
+echo $form->field($generator, 'ns');
+echo $form->field($generator, 'baseClass');
+echo $form->field($generator, 'db');
+echo $form->field($generator, 'useTablePrefix')->checkbox();
+echo $form->field($generator, 'generateRelations')->dropDownList([
+ Generator::RELATIONS_NONE => 'No relations',
+ Generator::RELATIONS_ALL => 'All relations',
+ Generator::RELATIONS_ALL_INVERSE => 'All relations with inverse',
+]);
+echo $form->field($generator, 'generateRelationsFromCurrentSchema')->checkbox();
+echo $form->field($generator, 'generateLabelsFromComments')->checkbox();
+echo $form->field($generator, 'generateQuery')->checkbox();
+echo $form->field($generator, 'queryNs');
+echo $form->field($generator, 'queryClass');
+echo $form->field($generator, 'queryBaseClass');
+echo $form->field($generator, 'enableI18N')->checkbox();
+echo $form->field($generator, 'messageCategory');
+echo $form->field($generator, 'useSchemaName')->checkbox();
From 32a7897adb59ccde6746488b8fa0f9fe357ef256 Mon Sep 17 00:00:00 2001
From: linyao <602604991@qq.com>
Date: Sat, 9 Nov 2019 10:17:48 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E6=A0=B9=E6=8D=AEvendor/blobt/generators/c?=
=?UTF-8?q?rud/=E5=88=9B=E5=BB=BAvendor/linyao/generators/crud/=E7=9A=84li?=
=?UTF-8?q?nyaocrud=E6=A8=A1=E6=9D=BF=E3=80=82=E5=88=A0=E5=87=8Fupdate.php?=
=?UTF-8?q?=E5=92=8Ccreate.php=E5=A4=9A=E4=BD=99=E5=AD=97=E6=A0=B7?=
=?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9view.php=E9=A1=B5=E9=9D=A2=E8=BF=94?=
=?UTF-8?q?=E5=9B=9E=E3=80=81=E4=BF=AE=E6=94=B9=E3=80=81=E5=88=A0=E9=99=A4?=
=?UTF-8?q?=E6=8C=89=E9=92=AE=E6=A0=B7=E5=BC=8F=E3=80=82=E4=BF=AE=E6=94=B9?=
=?UTF-8?q?gii=E7=9A=84linyaomodel=E6=A8=A1=E6=9D=BF=EF=BC=8C=E5=88=A0?=
=?UTF-8?q?=E9=99=A4rules=E7=8A=AF=E6=B3=95=E9=87=8C=E7=9A=84=E5=88=9B?=
=?UTF-8?q?=E5=BB=BA=E6=97=B6=E9=97=B4=E5=92=8C=E6=9B=B4=E6=96=B0=E6=97=B6?=
=?UTF-8?q?=E9=97=B4=E5=AD=97=E6=AE=B5=EF=BC=8C=E4=BD=BF=E5=BE=97=E6=A0=B9?=
=?UTF-8?q?=E6=8D=AEgii=E7=9A=84crud=E7=94=9F=E6=88=90=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E6=97=B6=EF=BC=8Cform=E8=A1=A8=E5=8D=95=E4=B8=8D=E7=94=9F?=
=?UTF-8?q?=E6=88=90=E5=88=9B=E5=BB=BA=E6=97=B6=E9=97=B4=E5=92=8C=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0=E6=97=B6=E9=97=B4=E5=AD=97=E6=AE=B5=E3=80=82=E8=8E=B7?=
=?UTF-8?q?=E5=8F=96blobt=E6=9C=80=E6=96=B0=E6=96=87=E4=BB=B6=E5=A4=B9?=
=?UTF-8?q?=E5=B9=B6=E6=9B=BF=E6=8D=A2=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../skeleton/kcadmin/config/main-local.php | 3 +-
vendor/blobt/generators/crud/Generator.php | 371 +++++++++++-
.../generators/crud/default/views/create.php | 2 +-
.../generators/crud/default/views/update.php | 2 +-
vendor/blobt/generators/crud/form.php | 17 +
vendor/linyao/generators/crud/Generator.php | 555 ++++++++++++++++++
.../generators/crud/default/controller.php | 179 ++++++
.../linyao/generators/crud/default/search.php | 86 +++
.../generators/crud/default/views/_form.php | 42 ++
.../generators/crud/default/views/_search.php | 45 ++
.../generators/crud/default/views/create.php | 27 +
.../generators/crud/default/views/index.php | 61 ++
.../generators/crud/default/views/update.php | 38 ++
.../generators/crud/default/views/view.php | 57 ++
vendor/linyao/generators/crud/form.php | 17 +
vendor/linyao/generators/model/Generator.php | 3 +
.../linyao/generators/model/default/model.php | 7 +
17 files changed, 1508 insertions(+), 4 deletions(-)
create mode 100644 vendor/blobt/generators/crud/form.php
create mode 100644 vendor/linyao/generators/crud/Generator.php
create mode 100644 vendor/linyao/generators/crud/default/controller.php
create mode 100644 vendor/linyao/generators/crud/default/search.php
create mode 100644 vendor/linyao/generators/crud/default/views/_form.php
create mode 100644 vendor/linyao/generators/crud/default/views/_search.php
create mode 100644 vendor/linyao/generators/crud/default/views/create.php
create mode 100644 vendor/linyao/generators/crud/default/views/index.php
create mode 100644 vendor/linyao/generators/crud/default/views/update.php
create mode 100644 vendor/linyao/generators/crud/default/views/view.php
create mode 100644 vendor/linyao/generators/crud/form.php
diff --git a/environments/skeleton/kcadmin/config/main-local.php b/environments/skeleton/kcadmin/config/main-local.php
index 47cc042..ddff7d3 100644
--- a/environments/skeleton/kcadmin/config/main-local.php
+++ b/environments/skeleton/kcadmin/config/main-local.php
@@ -22,9 +22,10 @@ if (!YII_ENV_TEST) {
'allowedIPs' => ['127.0.0.1'],
'generators' => [
'crud' => [
- 'class' => 'yii\gii\generators\crud\Generator',
+ 'class' => 'blobt\generators\crud\Generator',
'templates' => [
'blobtCrud' => '@blobt/generators/crud/default',
+ 'linyaoCrud' => '@linyao/generators/crud/default',
]
],
'model' => [
diff --git a/vendor/blobt/generators/crud/Generator.php b/vendor/blobt/generators/crud/Generator.php
index e306536..5a15825 100644
--- a/vendor/blobt/generators/crud/Generator.php
+++ b/vendor/blobt/generators/crud/Generator.php
@@ -24,7 +24,7 @@
* THE SOFTWARE.
*/
-namespace blobt\generators\curd;
+namespace blobt\generators\crud;
use Yii;
use yii\db\ActiveRecord;
@@ -51,6 +51,9 @@ class Generator extends \yii\gii\Generator {
public $indexWidgetType = 'grid';
public $searchModelClass = '';
+ public $enablePjax = false;
+ public $strictInflector = true;
+
/**
* {@inheritdoc}
*/
@@ -58,6 +61,77 @@ class Generator extends \yii\gii\Generator {
return 'CRUD Generator';
}
+ /**
+ * {@inheritdoc}
+ */
+ public function getDescription() {
+ return 'This generator generates a controller and views that implement CRUD (Create, Read, Update, Delete)
+ operations for the specified data model.';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rules() {
+ return array_merge(parent::rules(), [
+ [['controllerClass', 'modelClass', 'searchModelClass', 'baseControllerClass'], 'filter', 'filter' => 'trim'],
+ [['modelClass', 'controllerClass', 'baseControllerClass', 'indexWidgetType'], 'required'],
+ [['searchModelClass'], 'compare', 'compareAttribute' => 'modelClass', 'operator' => '!==', 'message' => 'Search Model Class must not be equal to Model Class.'],
+ [['modelClass', 'controllerClass', 'baseControllerClass', 'searchModelClass'], 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'],
+ [['modelClass'], 'validateClass', 'params' => ['extends' => BaseActiveRecord::className()]],
+ [['baseControllerClass'], 'validateClass', 'params' => ['extends' => Controller::className()]],
+ [['controllerClass'], 'match', 'pattern' => '/Controller$/', 'message' => 'Controller class name must be suffixed with "Controller".'],
+ [['controllerClass'], 'match', 'pattern' => '/(^|\\\\)[A-Z][^\\\\]+Controller$/', 'message' => 'Controller class name must start with an uppercase letter.'],
+ [['controllerClass', 'searchModelClass'], 'validateNewClass'],
+ [['indexWidgetType'], 'in', 'range' => ['grid', 'list']],
+ [['modelClass'], 'validateModelClass'],
+ [['enableI18N', 'enablePjax'], 'boolean'],
+ [['messageCategory'], 'validateMessageCategory', 'skipOnEmpty' => false],
+ ['viewPath', 'safe'],
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function attributeLabels() {
+ return array_merge(parent::attributeLabels(), [
+ 'modelClass' => 'Model Class',
+ 'controllerClass' => 'Controller Class',
+ 'viewPath' => 'View Path',
+ 'baseControllerClass' => 'Base Controller Class',
+ 'indexWidgetType' => 'Widget Used in Index Page',
+ 'searchModelClass' => 'Search Model Class',
+ 'enablePjax' => 'Enable Pjax',
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hints() {
+ return array_merge(parent::hints(), [
+ 'modelClass' => 'This is the ActiveRecord class associated with the table that CRUD will be built upon.
+ You should provide a fully qualified class name, e.g., app\models\Post
.',
+ 'controllerClass' => 'This is the name of the controller class to be generated. You should
+ provide a fully qualified namespaced class (e.g. app\controllers\PostController
),
+ and class name should be in CamelCase with an uppercase first letter. Make sure the class
+ is using the same namespace as specified by your application\'s controllerNamespace property.',
+ 'viewPath' => 'Specify the directory for storing the view scripts for the controller. You may use path alias here, e.g.,
+ /var/www/basic/controllers/views/post
, @app/views/post
. If not set, it will default
+ to @app/views/ControllerID
',
+ 'baseControllerClass' => 'This is the class that the new CRUD controller class will extend from.
+ You should provide a fully qualified class name, e.g., yii\web\Controller
.',
+ 'indexWidgetType' => 'This is the widget type to be used in the index page to display list of the models.
+ You may choose either GridView
or ListView
',
+ 'searchModelClass' => 'This is the name of the search model class to be generated. You should provide a fully
+ qualified namespaced class name, e.g., app\models\PostSearch
.',
+ 'enablePjax' => 'This indicates whether the generator should wrap the GridView
or ListView
+ widget on the index page with yii\widgets\Pjax
widget. Set this to true
if you want to get
+ sorting, filtering and pagination without page refreshing.',
+ ]);
+ }
+
/**
* {@inheritdoc}
*/
@@ -72,6 +146,18 @@ class Generator extends \yii\gii\Generator {
return array_merge(parent::stickyAttributes(), ['baseControllerClass', 'indexWidgetType']);
}
+ /**
+ * Checks if model class is valid
+ */
+ public function validateModelClass() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $pk = $class::primaryKey();
+ if (empty($pk)) {
+ $this->addError('modelClass', "The table associated with $class must have primary key(s).");
+ }
+ }
+
/**
* {@inheritdoc}
*/
@@ -183,4 +269,287 @@ class Generator extends \yii\gii\Generator {
return "\$form->field(\$model, '$attribute')->$input(['maxlength' => true])";
}
+ /**
+ * Generates column format
+ * @param \yii\db\ColumnSchema $column
+ * @return string
+ */
+ public function generateColumnFormat($column) {
+ if ($column->phpType === 'boolean') {
+ return 'boolean';
+ }
+
+ if ($column->type === 'text') {
+ return 'ntext';
+ }
+
+ if (stripos($column->name, 'time') !== false && $column->phpType === 'integer') {
+ return 'datetime';
+ }
+
+ if (stripos($column->name, 'email') !== false) {
+ return 'email';
+ }
+
+ if (preg_match('/(\b|[_-])url(\b|[_-])/i', $column->name)) {
+ return 'url';
+ }
+
+ return 'text';
+ }
+
+ /**
+ * Generates validation rules for the search model.
+ * @return array the generated validation rules
+ */
+ public function generateSearchRules()
+ {
+ if (($table = $this->getTableSchema()) === false) {
+ return ["[['" . implode("', '", $this->getColumnNames()) . "'], 'safe']"];
+ }
+ $types = [];
+ foreach ($table->columns as $column) {
+ switch ($column->type) {
+ case Schema::TYPE_TINYINT:
+ case Schema::TYPE_SMALLINT:
+ case Schema::TYPE_INTEGER:
+ case Schema::TYPE_BIGINT:
+ $types['integer'][] = $column->name;
+ break;
+ case Schema::TYPE_BOOLEAN:
+ $types['boolean'][] = $column->name;
+ break;
+ case Schema::TYPE_FLOAT:
+ case Schema::TYPE_DOUBLE:
+ case Schema::TYPE_DECIMAL:
+ case Schema::TYPE_MONEY:
+ $types['number'][] = $column->name;
+ break;
+ case Schema::TYPE_DATE:
+ case Schema::TYPE_TIME:
+ case Schema::TYPE_DATETIME:
+ case Schema::TYPE_TIMESTAMP:
+ default:
+ $types['safe'][] = $column->name;
+ break;
+ }
+ }
+
+ $rules = [];
+ foreach ($types as $type => $columns) {
+ $rules[] = "[['" . implode("', '", $columns) . "'], '$type']";
+ }
+
+ return $rules;
+ }
+
+ /**
+ * @return array searchable attributes
+ */
+ public function getSearchAttributes()
+ {
+ return $this->getColumnNames();
+ }
+
+ /**
+ * Generates the attribute labels for the search model.
+ * @return array the generated attribute labels (name => label)
+ */
+ public function generateSearchLabels()
+ {
+ /* @var $model \yii\base\Model */
+ $model = new $this->modelClass();
+ $attributeLabels = $model->attributeLabels();
+ $labels = [];
+ foreach ($this->getColumnNames() as $name) {
+ if (isset($attributeLabels[$name])) {
+ $labels[$name] = $attributeLabels[$name];
+ } else {
+ if (!strcasecmp($name, 'id')) {
+ $labels[$name] = 'ID';
+ } else {
+ $label = Inflector::camel2words($name);
+ if (!empty($label) && substr_compare($label, ' id', -3, 3, true) === 0) {
+ $label = substr($label, 0, -3) . ' ID';
+ }
+ $labels[$name] = $label;
+ }
+ }
+ }
+
+ return $labels;
+ }
+
+ /**
+ * Generates search conditions
+ * @return array
+ */
+ public function generateSearchConditions()
+ {
+ $columns = [];
+ if (($table = $this->getTableSchema()) === false) {
+ $class = $this->modelClass;
+ /* @var $model \yii\base\Model */
+ $model = new $class();
+ foreach ($model->attributes() as $attribute) {
+ $columns[$attribute] = 'unknown';
+ }
+ } else {
+ foreach ($table->columns as $column) {
+ $columns[$column->name] = $column->type;
+ }
+ }
+
+ $likeConditions = [];
+ $hashConditions = [];
+ foreach ($columns as $column => $type) {
+ switch ($type) {
+ case Schema::TYPE_TINYINT:
+ case Schema::TYPE_SMALLINT:
+ case Schema::TYPE_INTEGER:
+ case Schema::TYPE_BIGINT:
+ case Schema::TYPE_BOOLEAN:
+ case Schema::TYPE_FLOAT:
+ case Schema::TYPE_DOUBLE:
+ case Schema::TYPE_DECIMAL:
+ case Schema::TYPE_MONEY:
+ case Schema::TYPE_DATE:
+ case Schema::TYPE_TIME:
+ case Schema::TYPE_DATETIME:
+ case Schema::TYPE_TIMESTAMP:
+ $hashConditions[] = "'{$column}' => \$this->{$column},";
+ break;
+ default:
+ $likeKeyword = $this->getClassDbDriverName() === 'pgsql' ? 'ilike' : 'like';
+ $likeConditions[] = "->andFilterWhere(['{$likeKeyword}', '{$column}', \$this->{$column}])";
+ break;
+ }
+ }
+
+ $conditions = [];
+ if (!empty($hashConditions)) {
+ $conditions[] = "\$query->andFilterWhere([\n"
+ . str_repeat(' ', 12) . implode("\n" . str_repeat(' ', 12), $hashConditions)
+ . "\n" . str_repeat(' ', 8) . "]);\n";
+ }
+ if (!empty($likeConditions)) {
+ $conditions[] = "\$query" . implode("\n" . str_repeat(' ', 12), $likeConditions) . ";\n";
+ }
+
+ return $conditions;
+ }
+
+ /**
+ * Generates URL parameters
+ * @return string
+ */
+ public function generateUrlParams() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $pks = $class::primaryKey();
+ if (count($pks) === 1) {
+ if (is_subclass_of($class, 'yii\mongodb\ActiveRecord')) {
+ return "'id' => (string)\$model->{$pks[0]}";
+ }
+
+ return "'id' => \$model->{$pks[0]}";
+ }
+
+ $params = [];
+ foreach ($pks as $pk) {
+ if (is_subclass_of($class, 'yii\mongodb\ActiveRecord')) {
+ $params[] = "'$pk' => (string)\$model->$pk";
+ } else {
+ $params[] = "'$pk' => \$model->$pk";
+ }
+ }
+
+ return implode(', ', $params);
+ }
+
+ /**
+ * Generates action parameters
+ * @return string
+ */
+ public function generateActionParams() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $pks = $class::primaryKey();
+ if (count($pks) === 1) {
+ return '$id';
+ }
+
+ return '$' . implode(', $', $pks);
+ }
+
+ /**
+ * Generates parameter tags for phpdoc
+ * @return array parameter tags for phpdoc
+ */
+ public function generateActionParamComments() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $pks = $class::primaryKey();
+ if (($table = $this->getTableSchema()) === false) {
+ $params = [];
+ foreach ($pks as $pk) {
+ $params[] = '@param ' . (strtolower(substr($pk, -2)) === 'id' ? 'integer' : 'string') . ' $' . $pk;
+ }
+
+ return $params;
+ }
+ if (count($pks) === 1) {
+ return ['@param ' . $table->columns[$pks[0]]->phpType . ' $id'];
+ }
+
+ $params = [];
+ foreach ($pks as $pk) {
+ $params[] = '@param ' . $table->columns[$pk]->phpType . ' $' . $pk;
+ }
+
+ return $params;
+ }
+
+ /**
+ * Returns table schema for current model class or false if it is not an active record
+ * @return bool|\yii\db\TableSchema
+ */
+ public function getTableSchema() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ if (is_subclass_of($class, 'yii\db\ActiveRecord')) {
+ return $class::getTableSchema();
+ }
+
+ return false;
+ }
+
+ /**
+ * @return array model column names
+ */
+ public function getColumnNames() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ if (is_subclass_of($class, 'yii\db\ActiveRecord')) {
+ return $class::getTableSchema()->getColumnNames();
+ }
+
+ /* @var $model \yii\base\Model */
+ $model = new $class();
+
+ return $model->attributes();
+ }
+
+ /**
+ * @return string|null driver name of modelClass db connection.
+ * In case db is not instance of \yii\db\Connection null will be returned.
+ * @since 2.0.6
+ */
+ protected function getClassDbDriverName() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $db = $class::getDb();
+ return $db instanceof \yii\db\Connection ? $db->driverName : null;
+ }
+
}
diff --git a/vendor/blobt/generators/crud/default/views/create.php b/vendor/blobt/generators/crud/default/views/create.php
index 819bb3a..fe456dc 100644
--- a/vendor/blobt/generators/crud/default/views/create.php
+++ b/vendor/blobt/generators/crud/default/views/create.php
@@ -14,7 +14,7 @@ use yii\helpers\Html;
/* @var $this yii\web\View */
/* @var $model = ltrim($generator->modelClass, '\\') ?> */
-$this->title = = $generator->generateString('Create ' . Inflector::camel2words(StringHelper::basename($generator->modelClass))) ?>;
+$this->title = = $generator->generateString('创建 ' . Inflector::camel2words(StringHelper::basename($generator->modelClass))) ?>;
$this->params['breadcrumbs'][] = ['label' => = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
diff --git a/vendor/blobt/generators/crud/default/views/update.php b/vendor/blobt/generators/crud/default/views/update.php
index 31af000..4112451 100644
--- a/vendor/blobt/generators/crud/default/views/update.php
+++ b/vendor/blobt/generators/crud/default/views/update.php
@@ -27,7 +27,7 @@ use yii\helpers\Html;
$this->title = = $title ?>;
$this->params['breadcrumbs'][] = ['label' => = $generator->generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']];
$this->params['breadcrumbs'][] = ['label' => $model->= $generator->getNameAttribute() ?>, 'url' => ['view', = $urlParams ?>]];
-$this->params['breadcrumbs'][] = = $generator->generateString('Update') ?>;
+$this->params['breadcrumbs'][] = = $generator->generateString('Update ') ?>;
?>
app\models\Post
.',
+ 'controllerClass' => 'This is the name of the controller class to be generated. You should
+ provide a fully qualified namespaced class (e.g. app\controllers\PostController
),
+ and class name should be in CamelCase with an uppercase first letter. Make sure the class
+ is using the same namespace as specified by your application\'s controllerNamespace property.',
+ 'viewPath' => 'Specify the directory for storing the view scripts for the controller. You may use path alias here, e.g.,
+ /var/www/basic/controllers/views/post
, @app/views/post
. If not set, it will default
+ to @app/views/ControllerID
',
+ 'baseControllerClass' => 'This is the class that the new CRUD controller class will extend from.
+ You should provide a fully qualified class name, e.g., yii\web\Controller
.',
+ 'indexWidgetType' => 'This is the widget type to be used in the index page to display list of the models.
+ You may choose either GridView
or ListView
',
+ 'searchModelClass' => 'This is the name of the search model class to be generated. You should provide a fully
+ qualified namespaced class name, e.g., app\models\PostSearch
.',
+ 'enablePjax' => 'This indicates whether the generator should wrap the GridView
or ListView
+ widget on the index page with yii\widgets\Pjax
widget. Set this to true
if you want to get
+ sorting, filtering and pagination without page refreshing.',
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function requiredTemplates() {
+ return ['controller.php'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function stickyAttributes() {
+ return array_merge(parent::stickyAttributes(), ['baseControllerClass', 'indexWidgetType']);
+ }
+
+ /**
+ * Checks if model class is valid
+ */
+ public function validateModelClass() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $pk = $class::primaryKey();
+ if (empty($pk)) {
+ $this->addError('modelClass', "The table associated with $class must have primary key(s).");
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function generate() {
+ $controllerFile = Yii::getAlias('@' . str_replace('\\', '/', ltrim($this->controllerClass, '\\')) . '.php');
+
+ $files = [
+ new CodeFile($controllerFile, $this->render('controller.php')),
+ ];
+
+ if (!empty($this->searchModelClass)) {
+ $searchModel = Yii::getAlias('@' . str_replace('\\', '/', ltrim($this->searchModelClass, '\\') . '.php'));
+ $files[] = new CodeFile($searchModel, $this->render('search.php'));
+ }
+
+ $viewPath = $this->getViewPath();
+ $templatePath = $this->getTemplatePath() . '/views';
+ foreach (scandir($templatePath) as $file) {
+ if (empty($this->searchModelClass) && $file === '_search.php') {
+ continue;
+ }
+ if (is_file($templatePath . '/' . $file) && pathinfo($file, PATHINFO_EXTENSION) === 'php') {
+ $files[] = new CodeFile("$viewPath/$file", $this->render("views/$file"));
+ }
+ }
+
+ return $files;
+ }
+
+ /**
+ * @return string the controller ID (without the module ID prefix)
+ */
+ public function getControllerID() {
+ $pos = strrpos($this->controllerClass, '\\');
+ $class = substr(substr($this->controllerClass, $pos + 1), 0, -10);
+
+ return Inflector::camel2id($class, '-', $this->strictInflector);
+ }
+
+ /**
+ * @return string the controller view path
+ */
+ public function getViewPath() {
+ if (empty($this->viewPath)) {
+ return Yii::getAlias('@app/views/' . $this->getControllerID());
+ }
+
+ return Yii::getAlias(str_replace('\\', '/', $this->viewPath));
+ }
+
+ /**
+ * @return string
+ */
+ public function getNameAttribute() {
+ foreach ($this->getColumnNames() as $name) {
+ if (!strcasecmp($name, 'name') || !strcasecmp($name, 'title')) {
+ return $name;
+ }
+ }
+ /* @var $class \yii\db\ActiveRecord */
+ $class = $this->modelClass;
+ $pk = $class::primaryKey();
+
+ return $pk[0];
+ }
+
+ /**
+ * Generates code for active field
+ * @param string $attribute
+ * @return string
+ */
+ public function generateActiveField($attribute) {
+ $tableSchema = $this->getTableSchema();
+ if ($tableSchema === false || !isset($tableSchema->columns[$attribute])) {
+ if (preg_match('/^(password|pass|passwd|passcode)$/i', $attribute)) {
+ return "\$form->field(\$model, '$attribute')->passwordInput()";
+ }
+
+ return "\$form->field(\$model, '$attribute')";
+ }
+ $column = $tableSchema->columns[$attribute];
+ if ($column->phpType === 'boolean') {
+ return "\$form->field(\$model, '$attribute')->checkbox()";
+ }
+
+ if ($column->type === 'text') {
+ return "\$form->field(\$model, '$attribute')->textarea(['rows' => 6])";
+ }
+
+ if (preg_match('/^(password|pass|passwd|passcode)$/i', $column->name)) {
+ $input = 'passwordInput';
+ } else {
+ $input = 'textInput';
+ }
+
+ if (is_array($column->enumValues) && count($column->enumValues) > 0) {
+ $dropDownOptions = [];
+ foreach ($column->enumValues as $enumValue) {
+ $dropDownOptions[$enumValue] = Inflector::humanize($enumValue);
+ }
+ return "\$form->field(\$model, '$attribute')->dropDownList("
+ . preg_replace("/\n\s*/", ' ', VarDumper::export($dropDownOptions)) . ", ['prompt' => ''])";
+ }
+
+ if ($column->phpType !== 'string' || $column->size === null) {
+ return "\$form->field(\$model, '$attribute')->$input()";
+ }
+
+ return "\$form->field(\$model, '$attribute')->$input(['maxlength' => true])";
+ }
+
+ /**
+ * Generates column format
+ * @param \yii\db\ColumnSchema $column
+ * @return string
+ */
+ public function generateColumnFormat($column) {
+ if ($column->phpType === 'boolean') {
+ return 'boolean';
+ }
+
+ if ($column->type === 'text') {
+ return 'ntext';
+ }
+
+ if (stripos($column->name, 'time') !== false && $column->phpType === 'integer') {
+ return 'datetime';
+ }
+
+ if (stripos($column->name, 'email') !== false) {
+ return 'email';
+ }
+
+ if (preg_match('/(\b|[_-])url(\b|[_-])/i', $column->name)) {
+ return 'url';
+ }
+
+ return 'text';
+ }
+
+ /**
+ * Generates validation rules for the search model.
+ * @return array the generated validation rules
+ */
+ public function generateSearchRules()
+ {
+ if (($table = $this->getTableSchema()) === false) {
+ return ["[['" . implode("', '", $this->getColumnNames()) . "'], 'safe']"];
+ }
+ $types = [];
+ foreach ($table->columns as $column) {
+ switch ($column->type) {
+ case Schema::TYPE_TINYINT:
+ case Schema::TYPE_SMALLINT:
+ case Schema::TYPE_INTEGER:
+ case Schema::TYPE_BIGINT:
+ $types['integer'][] = $column->name;
+ break;
+ case Schema::TYPE_BOOLEAN:
+ $types['boolean'][] = $column->name;
+ break;
+ case Schema::TYPE_FLOAT:
+ case Schema::TYPE_DOUBLE:
+ case Schema::TYPE_DECIMAL:
+ case Schema::TYPE_MONEY:
+ $types['number'][] = $column->name;
+ break;
+ case Schema::TYPE_DATE:
+ case Schema::TYPE_TIME:
+ case Schema::TYPE_DATETIME:
+ case Schema::TYPE_TIMESTAMP:
+ default:
+ $types['safe'][] = $column->name;
+ break;
+ }
+ }
+
+ $rules = [];
+ foreach ($types as $type => $columns) {
+ $rules[] = "[['" . implode("', '", $columns) . "'], '$type']";
+ }
+
+ return $rules;
+ }
+
+ /**
+ * @return array searchable attributes
+ */
+ public function getSearchAttributes()
+ {
+ return $this->getColumnNames();
+ }
+
+ /**
+ * Generates the attribute labels for the search model.
+ * @return array the generated attribute labels (name => label)
+ */
+ public function generateSearchLabels()
+ {
+ /* @var $model \yii\base\Model */
+ $model = new $this->modelClass();
+ $attributeLabels = $model->attributeLabels();
+ $labels = [];
+ foreach ($this->getColumnNames() as $name) {
+ if (isset($attributeLabels[$name])) {
+ $labels[$name] = $attributeLabels[$name];
+ } else {
+ if (!strcasecmp($name, 'id')) {
+ $labels[$name] = 'ID';
+ } else {
+ $label = Inflector::camel2words($name);
+ if (!empty($label) && substr_compare($label, ' id', -3, 3, true) === 0) {
+ $label = substr($label, 0, -3) . ' ID';
+ }
+ $labels[$name] = $label;
+ }
+ }
+ }
+
+ return $labels;
+ }
+
+ /**
+ * Generates search conditions
+ * @return array
+ */
+ public function generateSearchConditions()
+ {
+ $columns = [];
+ if (($table = $this->getTableSchema()) === false) {
+ $class = $this->modelClass;
+ /* @var $model \yii\base\Model */
+ $model = new $class();
+ foreach ($model->attributes() as $attribute) {
+ $columns[$attribute] = 'unknown';
+ }
+ } else {
+ foreach ($table->columns as $column) {
+ $columns[$column->name] = $column->type;
+ }
+ }
+
+ $likeConditions = [];
+ $hashConditions = [];
+ foreach ($columns as $column => $type) {
+ switch ($type) {
+ case Schema::TYPE_TINYINT:
+ case Schema::TYPE_SMALLINT:
+ case Schema::TYPE_INTEGER:
+ case Schema::TYPE_BIGINT:
+ case Schema::TYPE_BOOLEAN:
+ case Schema::TYPE_FLOAT:
+ case Schema::TYPE_DOUBLE:
+ case Schema::TYPE_DECIMAL:
+ case Schema::TYPE_MONEY:
+ case Schema::TYPE_DATE:
+ case Schema::TYPE_TIME:
+ case Schema::TYPE_DATETIME:
+ case Schema::TYPE_TIMESTAMP:
+ $hashConditions[] = "'{$column}' => \$this->{$column},";
+ break;
+ default:
+ $likeKeyword = $this->getClassDbDriverName() === 'pgsql' ? 'ilike' : 'like';
+ $likeConditions[] = "->andFilterWhere(['{$likeKeyword}', '{$column}', \$this->{$column}])";
+ break;
+ }
+ }
+
+ $conditions = [];
+ if (!empty($hashConditions)) {
+ $conditions[] = "\$query->andFilterWhere([\n"
+ . str_repeat(' ', 12) . implode("\n" . str_repeat(' ', 12), $hashConditions)
+ . "\n" . str_repeat(' ', 8) . "]);\n";
+ }
+ if (!empty($likeConditions)) {
+ $conditions[] = "\$query" . implode("\n" . str_repeat(' ', 12), $likeConditions) . ";\n";
+ }
+
+ return $conditions;
+ }
+
+ /**
+ * Generates URL parameters
+ * @return string
+ */
+ public function generateUrlParams() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $pks = $class::primaryKey();
+ if (count($pks) === 1) {
+ if (is_subclass_of($class, 'yii\mongodb\ActiveRecord')) {
+ return "'id' => (string)\$model->{$pks[0]}";
+ }
+
+ return "'id' => \$model->{$pks[0]}";
+ }
+
+ $params = [];
+ foreach ($pks as $pk) {
+ if (is_subclass_of($class, 'yii\mongodb\ActiveRecord')) {
+ $params[] = "'$pk' => (string)\$model->$pk";
+ } else {
+ $params[] = "'$pk' => \$model->$pk";
+ }
+ }
+
+ return implode(', ', $params);
+ }
+
+ /**
+ * Generates action parameters
+ * @return string
+ */
+ public function generateActionParams() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $pks = $class::primaryKey();
+ if (count($pks) === 1) {
+ return '$id';
+ }
+
+ return '$' . implode(', $', $pks);
+ }
+
+ /**
+ * Generates parameter tags for phpdoc
+ * @return array parameter tags for phpdoc
+ */
+ public function generateActionParamComments() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $pks = $class::primaryKey();
+ if (($table = $this->getTableSchema()) === false) {
+ $params = [];
+ foreach ($pks as $pk) {
+ $params[] = '@param ' . (strtolower(substr($pk, -2)) === 'id' ? 'integer' : 'string') . ' $' . $pk;
+ }
+
+ return $params;
+ }
+ if (count($pks) === 1) {
+ return ['@param ' . $table->columns[$pks[0]]->phpType . ' $id'];
+ }
+
+ $params = [];
+ foreach ($pks as $pk) {
+ $params[] = '@param ' . $table->columns[$pk]->phpType . ' $' . $pk;
+ }
+
+ return $params;
+ }
+
+ /**
+ * Returns table schema for current model class or false if it is not an active record
+ * @return bool|\yii\db\TableSchema
+ */
+ public function getTableSchema() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ if (is_subclass_of($class, 'yii\db\ActiveRecord')) {
+ return $class::getTableSchema();
+ }
+
+ return false;
+ }
+
+ /**
+ * @return array model column names
+ */
+ public function getColumnNames() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ if (is_subclass_of($class, 'yii\db\ActiveRecord')) {
+ return $class::getTableSchema()->getColumnNames();
+ }
+
+ /* @var $model \yii\base\Model */
+ $model = new $class();
+
+ return $model->attributes();
+ }
+
+ /**
+ * @return string|null driver name of modelClass db connection.
+ * In case db is not instance of \yii\db\Connection null will be returned.
+ * @since 2.0.6
+ */
+ protected function getClassDbDriverName() {
+ /* @var $class ActiveRecord */
+ $class = $this->modelClass;
+ $db = $class::getDb();
+ return $db instanceof \yii\db\Connection ? $db->driverName : null;
+ }
+
+}
diff --git a/vendor/linyao/generators/crud/default/controller.php b/vendor/linyao/generators/crud/default/controller.php
new file mode 100644
index 0000000..b7049e7
--- /dev/null
+++ b/vendor/linyao/generators/crud/default/controller.php
@@ -0,0 +1,179 @@
+controllerClass);
+$modelClass = StringHelper::basename($generator->modelClass);
+$searchModelClass = StringHelper::basename($generator->searchModelClass);
+if ($modelClass === $searchModelClass) {
+ $searchModelAlias = $searchModelClass . 'Search';
+}
+
+/* @var $class ActiveRecordInterface */
+$class = $generator->modelClass;
+$pks = $class::primaryKey();
+$urlParams = $generator->generateUrlParams();
+$actionParams = $generator->generateActionParams();
+$actionParamComments = $generator->generateActionParamComments();
+
+echo "
+
+namespace = StringHelper::dirname(ltrim($generator->controllerClass, '\\')) ?>;
+
+use Yii;
+use = ltrim($generator->modelClass, '\\') ?>;
+searchModelClass)): ?>
+use = ltrim($generator->searchModelClass, '\\') . (isset($searchModelAlias) ? " as $searchModelAlias" : "") ?>;
+
+use yii\data\ActiveDataProvider;
+
+use = ltrim($generator->baseControllerClass, '\\') ?>;
+use yii\web\NotFoundHttpException;
+use yii\filters\VerbFilter;
+
+/**
+ * = $controllerClass ?> implements the CRUD actions for = $modelClass ?> model.
+ */
+class = $controllerClass ?> extends = StringHelper::basename($generator->baseControllerClass) . "\n" ?>
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return [
+ 'verbs' => [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'delete' => ['POST'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Lists all = $modelClass ?> models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+searchModelClass)): ?>
+ $searchModel = new = isset($searchModelAlias) ? $searchModelAlias : $searchModelClass ?>();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => = $modelClass ?>::find(),
+ ]);
+
+ return $this->render('index', [
+ 'dataProvider' => $dataProvider,
+ ]);
+
+ }
+
+ /**
+ * Displays a single = $modelClass ?> model.
+ * = implode("\n * ", $actionParamComments) . "\n" ?>
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView(= $actionParams ?>)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel(= $actionParams ?>),
+ ]);
+ }
+
+ /**
+ * Creates a new = $modelClass ?> model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new = $modelClass ?>();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', = $urlParams ?>]);
+ }
+
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing = $modelClass ?> model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * = implode("\n * ", $actionParamComments) . "\n" ?>
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate(= $actionParams ?>)
+ {
+ $model = $this->findModel(= $actionParams ?>);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', = $urlParams ?>]);
+ }
+
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing = $modelClass ?> model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * = implode("\n * ", $actionParamComments) . "\n" ?>
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete(= $actionParams ?>)
+ {
+ $this->findModel(= $actionParams ?>)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the = $modelClass ?> model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * = implode("\n * ", $actionParamComments) . "\n" ?>
+ * @return = $modelClass ?> the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel(= $actionParams ?>)
+ {
+ \$$pk";
+ }
+ $condition = '[' . implode(', ', $condition) . ']';
+}
+?>
+ if (($model = = $modelClass ?>::findOne(= $condition ?>)) !== null) {
+ return $model;
+ }
+
+ throw new NotFoundHttpException(= $generator->generateString('The requested page does not exist.') ?>);
+ }
+}
diff --git a/vendor/linyao/generators/crud/default/search.php b/vendor/linyao/generators/crud/default/search.php
new file mode 100644
index 0000000..0ca91d4
--- /dev/null
+++ b/vendor/linyao/generators/crud/default/search.php
@@ -0,0 +1,86 @@
+modelClass);
+$searchModelClass = StringHelper::basename($generator->searchModelClass);
+if ($modelClass === $searchModelClass) {
+ $modelAlias = $modelClass . 'Model';
+}
+$rules = $generator->generateSearchRules();
+$labels = $generator->generateSearchLabels();
+$searchAttributes = $generator->getSearchAttributes();
+$searchConditions = $generator->generateSearchConditions();
+
+echo "
+
+namespace = StringHelper::dirname(ltrim($generator->searchModelClass, '\\')) ?>;
+
+use yii\base\Model;
+use yii\data\ActiveDataProvider;
+use = ltrim($generator->modelClass, '\\') . (isset($modelAlias) ? " as $modelAlias" : "") ?>;
+
+/**
+ * = $searchModelClass ?> represents the model behind the search form of `= $generator->modelClass ?>`.
+ */
+class = $searchModelClass ?> extends = isset($modelAlias) ? $modelAlias : $modelClass ?>
+
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function rules()
+ {
+ return [
+ = implode(",\n ", $rules) ?>,
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function scenarios()
+ {
+ // bypass scenarios() implementation in the parent class
+ return Model::scenarios();
+ }
+
+ /**
+ * Creates data provider instance with search query applied
+ *
+ * @param array $params
+ *
+ * @return ActiveDataProvider
+ */
+ public function search($params)
+ {
+ $query = = isset($modelAlias) ? $modelAlias : $modelClass ?>::find();
+
+ // add conditions that should always apply here
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => $query,
+ ]);
+
+ $this->load($params);
+
+ if (!$this->validate()) {
+ // uncomment the following line if you do not want to return any records when validation fails
+ // $query->where('0=1');
+ return $dataProvider;
+ }
+
+ // grid filtering conditions
+ = implode("\n ", $searchConditions) ?>
+
+ return $dataProvider;
+ }
+}
diff --git a/vendor/linyao/generators/crud/default/views/_form.php b/vendor/linyao/generators/crud/default/views/_form.php
new file mode 100644
index 0000000..bdfd766
--- /dev/null
+++ b/vendor/linyao/generators/crud/default/views/_form.php
@@ -0,0 +1,42 @@
+modelClass();
+$safeAttributes = $model->safeAttributes();
+if (empty($safeAttributes)) {
+ $safeAttributes = $model->attributes();
+}
+
+echo "
+
+use yii\helpers\Html;
+use yii\widgets\ActiveForm;
+
+/* @var $this yii\web\View */
+/* @var $model = ltrim($generator->modelClass, '\\') ?> */
+/* @var $form yii\widgets\ActiveForm */
+?>
+
++ = "= " ?>Html::a(= $generator->generateString('返回列表') ?>, ['index'], ['class' => 'btn btn-success']) ?> + = "= " ?>Html::a(= $generator->generateString('编辑') ?>, ['update', = $urlParams ?>], ['class' => 'btn btn-primary']) ?> + = "= " ?>Html::a(= $generator->generateString('删除') ?>, ['delete', = $urlParams ?>], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => = $generator->generateString('确定要删除该条记录吗?') ?>, + 'method' => 'post', + ], + ]) ?> +
+ + = "= " ?>DetailView::widget([ + 'model' => $model, + 'attributes' => [ +getTableSchema()) === false) { + foreach ($generator->getColumnNames() as $name) { + echo " '" . $name . "',\n"; + } +} else { + foreach ($generator->getTableSchema()->columns as $column) { + $format = $generator->generateColumnFormat($column); + echo " '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n"; + } +} +?> + ], + ]) ?> + += "= " ?>Html::a(= $generator->generateString('返回列表') ?>, ['index'], ['class' => 'btn btn-success']) ?> - = "= " ?>Html::a(= $generator->generateString('编辑') ?>, ['update', = $urlParams ?>], ['class' => 'btn btn-primary']) ?> - = "= " ?>Html::a(= $generator->generateString('删除') ?>, ['delete', = $urlParams ?>], [ - 'class' => 'btn btn-danger', - 'data' => [ - 'confirm' => = $generator->generateString('确定要删除该条记录吗?') ?>, - 'method' => 'post', - ], - ]) ?>
= "= " ?>DetailView::widget([