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 modelClass, '\\') ?> */ -$this->title = generateString('Create ' . Inflector::camel2words(StringHelper::basename($generator->modelClass))) ?>; +$this->title = generateString('创建 ' . Inflector::camel2words(StringHelper::basename($generator->modelClass))) ?>; $this->params['breadcrumbs'][] = ['label' => 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 = ; $this->params['breadcrumbs'][] = ['label' => generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']]; $this->params['breadcrumbs'][] = ['label' => $model->getNameAttribute() ?>, 'url' => ['view', ]]; -$this->params['breadcrumbs'][] = generateString('Update') ?>; +$this->params['breadcrumbs'][] = generateString('Update ') ?>; ?>
diff --git a/vendor/blobt/generators/crud/form.php b/vendor/blobt/generators/crud/form.php new file mode 100644 index 0000000..4f59b8b --- /dev/null +++ b/vendor/blobt/generators/crud/form.php @@ -0,0 +1,17 @@ +field($generator, 'modelClass'); +echo $form->field($generator, 'searchModelClass'); +echo $form->field($generator, 'controllerClass'); +echo $form->field($generator, 'viewPath'); +echo $form->field($generator, 'baseControllerClass'); +echo $form->field($generator, 'indexWidgetType')->dropDownList([ + 'grid' => 'GridView', + 'list' => 'ListView', +]); +echo $form->field($generator, 'enableI18N')->checkbox(); +echo $form->field($generator, 'enablePjax')->checkbox(); +echo $form->field($generator, 'messageCategory'); diff --git a/vendor/linyao/generators/crud/Generator.php b/vendor/linyao/generators/crud/Generator.php new file mode 100644 index 0000000..5a15825 --- /dev/null +++ b/vendor/linyao/generators/crud/Generator.php @@ -0,0 +1,555 @@ + '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} + */ + 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 controllerClass, '\\')) ?>; + +use Yii; +use modelClass, '\\') ?>; +searchModelClass)): ?> +use searchModelClass, '\\') . (isset($searchModelAlias) ? " as $searchModelAlias" : "") ?>; + +use yii\data\ActiveDataProvider; + +use baseControllerClass, '\\') ?>; +use yii\web\NotFoundHttpException; +use yii\filters\VerbFilter; + +/** + * implements the CRUD actions for model. + */ +class extends baseControllerClass) . "\n" ?> +{ + /** + * {@inheritdoc} + */ + public function behaviors() + { + return [ + 'verbs' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ]; + } + + /** + * Lists all models. + * @return mixed + */ + public function actionIndex() + { +searchModelClass)): ?> + $searchModel = new (); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + + $dataProvider = new ActiveDataProvider([ + 'query' => ::find(), + ]); + + return $this->render('index', [ + 'dataProvider' => $dataProvider, + ]); + + } + + /** + * Displays a single model. + * + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionView() + { + return $this->render('view', [ + 'model' => $this->findModel(), + ]); + } + + /** + * Creates a new model. + * If creation is successful, the browser will be redirected to the 'view' page. + * @return mixed + */ + public function actionCreate() + { + $model = new (); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', ]); + } + + return $this->render('create', [ + 'model' => $model, + ]); + } + + /** + * Updates an existing model. + * If update is successful, the browser will be redirected to the 'view' page. + * + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionUpdate() + { + $model = $this->findModel(); + + if ($model->load(Yii::$app->request->post()) && $model->save()) { + return $this->redirect(['view', ]); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Deletes an existing model. + * If deletion is successful, the browser will be redirected to the 'index' page. + * + * @return mixed + * @throws NotFoundHttpException if the model cannot be found + */ + public function actionDelete() + { + $this->findModel()->delete(); + + return $this->redirect(['index']); + } + + /** + * Finds the model based on its primary key value. + * If the model is not found, a 404 HTTP exception will be thrown. + * + * @return the loaded model + * @throws NotFoundHttpException if the model cannot be found + */ + protected function findModel() + { + \$$pk"; + } + $condition = '[' . implode(', ', $condition) . ']'; +} +?> + if (($model = ::findOne()) !== null) { + return $model; + } + + throw new NotFoundHttpException(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 searchModelClass, '\\')) ?>; + +use yii\base\Model; +use yii\data\ActiveDataProvider; +use modelClass, '\\') . (isset($modelAlias) ? " as $modelAlias" : "") ?>; + +/** + * represents the model behind the search form of `modelClass ?>`. + */ +class extends + +{ + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + , + ]; + } + + /** + * {@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 = ::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 + + + 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 modelClass, '\\') ?> */ +/* @var $form yii\widgets\ActiveForm */ +?> + +
+ + $form = ActiveForm::begin(); ?> + +getColumnNames() as $attribute) { + if (in_array($attribute, $safeAttributes)) { + echo " generateActiveField($attribute) . " ?>\n\n"; + } +} ?> +
+ Html::submitButton(generateString('保存') ?>, ['class' => 'btn btn-success']) ?> +
+ + ActiveForm::end(); ?> + +
diff --git a/vendor/linyao/generators/crud/default/views/_search.php b/vendor/linyao/generators/crud/default/views/_search.php new file mode 100644 index 0000000..e7efb17 --- /dev/null +++ b/vendor/linyao/generators/crud/default/views/_search.php @@ -0,0 +1,45 @@ + + +use yii\helpers\Html; +use yii\widgets\ActiveForm; + +/* @var $this yii\web\View */ +/* @var $model searchModelClass, '\\') ?> */ +/* @var $form yii\widgets\ActiveForm */ +?> + +$form = ActiveForm::begin([ + 'action' => ['index'], + 'method' => 'get', + 'validateOnType' => true, + ]); +?> +
+
+ $form->field($model, 'id', [ + "template" => "{input}{error}", + "inputOptions" => [ + "placeholder" => "检索ID", + "class" => "form-control", + ], + "errorOptions" => [ + "class" => "error-tips" + ] + ]) + ?> +
+ Html::submitButton('', ['class' => 'btn btn-default']) ?> + Html::resetButton('', ['class' => 'btn btn-default']) ?> +
+
+
+ActiveForm::end(); ?> \ No newline at end of file diff --git a/vendor/linyao/generators/crud/default/views/create.php b/vendor/linyao/generators/crud/default/views/create.php new file mode 100644 index 0000000..af66141 --- /dev/null +++ b/vendor/linyao/generators/crud/default/views/create.php @@ -0,0 +1,27 @@ + + +use yii\helpers\Html; + +/* @var $this yii\web\View */ +/* @var $model modelClass, '\\') ?> */ + +$this->title = generateString('创建 ' . Inflector::camel2words(StringHelper::basename($generator->modelClass))) ?>; +$this->params['breadcrumbs'][] = ['label' => generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +?> +
+ + $this->render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/vendor/linyao/generators/crud/default/views/index.php b/vendor/linyao/generators/crud/default/views/index.php new file mode 100644 index 0000000..3a21f39 --- /dev/null +++ b/vendor/linyao/generators/crud/default/views/index.php @@ -0,0 +1,61 @@ +generateUrlParams(); +$nameAttribute = $generator->getNameAttribute(); + +echo " + +use yii\helpers\Html; +use blobt\grid\GridView; + +/* @var $this yii\web\View */ +searchModelClass) ? "/* @var \$searchModel " . ltrim($generator->searchModelClass, '\\') . " */\n" : '' ?> +/* @var $dataProvider yii\data\ActiveDataProvider */ + +$this->title = generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>; +$this->params['breadcrumbs'][] = $this->title; +?> +
+
+ GridView::widget([ + 'dataProvider' => $dataProvider, + 'filter' => $this->render("_search", ['model' => $searchModel]), + 'batch' => [ + [ + "label" => "删除", + "url" => "controllerID?>/deletes" + ], + ], + 'columns' => [ + [ + 'class' => 'blobt\grid\CheckboxColumn', + 'width' => '2%', + 'align' => 'center' + ], +getColumnNames() as $name) { + if (++$count < 6) { + echo " '" . $name . "',\n"; + } else { + echo " //'" . $name . "',\n"; + } + } +?> + [ + 'class' => 'blobt\grid\ActionColumn', + 'align' => 'center' + ], + ] + ]); + " ?> +
+
\ No newline at end of file diff --git a/vendor/linyao/generators/crud/default/views/update.php b/vendor/linyao/generators/crud/default/views/update.php new file mode 100644 index 0000000..94cadc6 --- /dev/null +++ b/vendor/linyao/generators/crud/default/views/update.php @@ -0,0 +1,38 @@ +generateUrlParams(); +$modelClassName = Inflector::camel2words(StringHelper::basename($generator->modelClass)); +$nameAttributeTemplate = '$model->' . $generator->getNameAttribute(); +$titleTemplate = $generator->generateString('Update ' . $modelClassName . ': {name}', ['name' => '{nameAttribute}']); +if ($generator->enableI18N) { + $title = strtr($titleTemplate, ['\'{nameAttribute}\'' => $nameAttributeTemplate]); +} else { + $title = strtr($titleTemplate, ['{nameAttribute}\'' => '\' . ' . $nameAttributeTemplate]); +} + +echo " + +use yii\helpers\Html; + +/* @var $this yii\web\View */ +/* @var $model modelClass, '\\') ?> */ + +$this->title = ; +$this->params['breadcrumbs'][] = ['label' => generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']]; +$this->params['breadcrumbs'][] = ['label' => $model->getNameAttribute() ?>, 'url' => ['view', ]]; +$this->params['breadcrumbs'][] = generateString('Update ') ?>; +?> +
+ + $this->render('_form', [ + 'model' => $model, + ]) ?> + +
diff --git a/vendor/linyao/generators/crud/default/views/view.php b/vendor/linyao/generators/crud/default/views/view.php new file mode 100644 index 0000000..1c1e2f9 --- /dev/null +++ b/vendor/linyao/generators/crud/default/views/view.php @@ -0,0 +1,57 @@ +generateUrlParams(); + +echo " + +use yii\helpers\Html; +use yii\widgets\DetailView; + +/* @var $this yii\web\View */ +/* @var $model modelClass, '\\') ?> */ + +$this->title = $model->getNameAttribute() ?>; +$this->params['breadcrumbs'][] = ['label' => generateString(Inflector::pluralize(Inflector::camel2words(StringHelper::basename($generator->modelClass)))) ?>, 'url' => ['index']]; +$this->params['breadcrumbs'][] = $this->title; +\yii\web\YiiAsset::register($this); +?> +
+ +

+ Html::a(generateString('返回列表') ?>, ['index'], ['class' => 'btn btn-success']) ?> + Html::a(generateString('编辑') ?>, ['update', ], ['class' => 'btn btn-primary']) ?> + Html::a(generateString('删除') ?>, ['delete', ], [ + 'class' => 'btn btn-danger', + 'data' => [ + 'confirm' => 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"; + } +} +?> + ], + ]) ?> + +
diff --git a/vendor/linyao/generators/crud/form.php b/vendor/linyao/generators/crud/form.php new file mode 100644 index 0000000..4f59b8b --- /dev/null +++ b/vendor/linyao/generators/crud/form.php @@ -0,0 +1,17 @@ +field($generator, 'modelClass'); +echo $form->field($generator, 'searchModelClass'); +echo $form->field($generator, 'controllerClass'); +echo $form->field($generator, 'viewPath'); +echo $form->field($generator, 'baseControllerClass'); +echo $form->field($generator, 'indexWidgetType')->dropDownList([ + 'grid' => 'GridView', + 'list' => 'ListView', +]); +echo $form->field($generator, 'enableI18N')->checkbox(); +echo $form->field($generator, 'enablePjax')->checkbox(); +echo $form->field($generator, 'messageCategory'); diff --git a/vendor/linyao/generators/model/Generator.php b/vendor/linyao/generators/model/Generator.php index fe7d4d1..be3097f 100644 --- a/vendor/linyao/generators/model/Generator.php +++ b/vendor/linyao/generators/model/Generator.php @@ -335,6 +335,9 @@ class Generator extends \yii\gii\Generator $types = []; $lengths = []; foreach ($table->columns as $column) { + if($column->name == 'created_at' || $column->name == 'updated_at') { + continue; + } if ($column->autoIncrement) { continue; } diff --git a/vendor/linyao/generators/model/default/model.php b/vendor/linyao/generators/model/default/model.php index 99d57e7..a04b695 100644 --- a/vendor/linyao/generators/model/default/model.php +++ b/vendor/linyao/generators/model/default/model.php @@ -100,6 +100,13 @@ class extends baseClass, '\\') . + /** + * @author linyao + * @email 602604991@qq.com + * @created Nov 8, 2019 + * + * 行为存储创建时间和更新时间 + */ public function behaviors() { return [