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] =?UTF-8?q?=E6=A0=B9=E6=8D=AEvendor/blobt/generators/crud/?=
=?UTF-8?q?=E5=88=9B=E5=BB=BAvendor/linyao/generators/crud/=E7=9A=84linyao?=
=?UTF-8?q?crud=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"; + } +} +?> + ], + ]) ?> + +