diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php
index 1b7bf5b..de75ce7 100644
--- a/framework/yii/base/Module.php
+++ b/framework/yii/base/Module.php
@@ -338,10 +338,9 @@ abstract class Module extends Component
/**
* Retrieves the named module.
- * @param string $id module ID (case-sensitive)
+ * @param string $id module ID (case-sensitive).
* @param boolean $load whether to load the module if it is not yet loaded.
- * @return Module|null the module instance, null if the module
- * does not exist.
+ * @return Module|null the module instance, null if the module does not exist.
* @see hasModule()
*/
public function getModule($id, $load = true)
diff --git a/framework/yii/gii/Generator.php b/framework/yii/gii/Generator.php
index f79b428..eb5b8b4 100644
--- a/framework/yii/gii/Generator.php
+++ b/framework/yii/gii/Generator.php
@@ -325,6 +325,28 @@ abstract class Generator extends Model
}
/**
+ * An inline validator that checks if the attribute value refers to a valid namespaced class name.
+ * The validator will check if the directory containing the new class file exist or not.
+ * @param string $attribute the attribute being validated
+ * @param array $params the validation options
+ */
+ public function validateNewClass($attribute, $params)
+ {
+ $class = ltrim($this->$attribute, '\\');
+ if (($pos = strrpos($class, '\\')) === false) {
+ $this->addError($attribute, "The class name must contain fully qualified namespace name.");
+ } else {
+ $ns = substr($class, 0, $pos);
+ $path = Yii::getAlias('@' . str_replace('\\', '/', $ns), false);
+ if ($path === false) {
+ $this->addError($attribute, "The class namespace is invalid: $ns");
+ } elseif (!is_dir($path)) {
+ $this->addError($attribute, "Please make sure the directory containing this class exists: $path");
+ }
+ }
+ }
+
+ /**
* @param string $value the attribute to be validated
* @return boolean whether the value is a reserved PHP keyword.
*/
diff --git a/framework/yii/gii/assets/gii.js b/framework/yii/gii/assets/gii.js
index b581d3b..45951a1 100644
--- a/framework/yii/gii/assets/gii.js
+++ b/framework/yii/gii/assets/gii.js
@@ -81,6 +81,11 @@ yii.gii = (function ($) {
$('#model-generator .field-generator-modelclass').toggle($(this).val().indexOf('*') == -1);
}).change();
+ // crud generator: hide Search Model Class input if search is not enabled
+ $('#crud-generator #generator-enablesearch').on('change', function () {
+ $('#crud-generator .field-generator-searchmodelclass').toggle(this.checked);
+ }).change();
+
// hide Generate button if any input is changed
$('.default-view .form-group input,select,textarea').change(function () {
$('.default-view-results,.default-view-files').hide();
diff --git a/framework/yii/gii/generators/crud/Generator.php b/framework/yii/gii/generators/crud/Generator.php
index 983dbc7..3ed51c1 100644
--- a/framework/yii/gii/generators/crud/Generator.php
+++ b/framework/yii/gii/generators/crud/Generator.php
@@ -22,7 +22,8 @@ use yii\web\Controller;
class Generator extends \yii\gii\Generator
{
public $modelClass;
- public $controllerID;
+ public $moduleID;
+ public $controllerClass;
public $baseControllerClass = 'yii\web\Controller';
public $indexWidgetType = 'grid';
public $enableSearch = true;
@@ -42,16 +43,18 @@ class Generator extends \yii\gii\Generator
public function rules()
{
return array_merge(parent::rules(), array(
- array('modelClass, searchModelClass, controllerID, baseControllerClass', 'filter', 'filter' => 'trim'),
- array('modelClass, controllerID, baseControllerClass', 'required'),
- array('modelClass, searchModelClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'),
+ array('moduleID, controllerClass, modelClass, searchModelClass, baseControllerClass', 'filter', 'filter' => 'trim'),
+ array('modelClass, controllerClass, baseControllerClass, indexWidgetType', 'required'),
+ array('modelClass, controllerClass, baseControllerClass, searchModelClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'),
array('modelClass', 'validateClass', 'params' => array('extends' => ActiveRecord::className())),
- array('controllerID', 'match', 'pattern' => '/^[a-z\\-\\/]*$/', 'message' => 'Only a-z, dashes (-) and slashes (/) are allowed.'),
- array('baseControllerClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'),
array('baseControllerClass', 'validateClass', 'params' => array('extends' => Controller::className())),
+ array('controllerClass', 'match', 'pattern' => '/Controller$/', 'message' => 'Controller class name must be suffixed with "Controller".'),
+ array('controllerClass, searchModelClass', 'validateNewClass'),
array('enableSearch', 'boolean'),
array('indexWidgetType', 'in', 'range' => array('grid', 'list')),
+ array('modelClass', 'validateModelClass'),
array('searchModelClass', 'validateSearchModelClass'),
+ array('moduleID', 'validateModuleID'),
));
}
@@ -59,7 +62,8 @@ class Generator extends \yii\gii\Generator
{
return array_merge(parent::attributeLabels(), array(
'modelClass' => 'Model Class',
- 'controllerID' => 'Controller ID',
+ 'moduleID' => 'Module ID',
+ 'controllerClass' => 'Controller Class',
'baseControllerClass' => 'Base Controller Class',
'indexWidgetType' => 'Widget Used in Index Page',
'enableSearch' => 'Enable Search',
@@ -75,15 +79,12 @@ class Generator extends \yii\gii\Generator
return array(
'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
.',
- 'controllerID' => 'CRUD controllers are often named after the model class name that they are dealing with.
- Controller ID should be in lower case and may contain module ID(s) separated by slashes. For example:
-
order
generates OrderController.php
order-item
generates OrderItemController.php
admin/user
generates UserController.php
within the admin
module.app\controllers\PostController
.',
'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
.',
+ 'moduleID' => 'This is the ID of the module that the generated controller will belong to.
+ If not set, it means the controller will belong to the application.',
'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
',
'enableSearch' => 'Whether to enable the search functionality on the index page. When search is enabled,
@@ -106,7 +107,17 @@ class Generator extends \yii\gii\Generator
*/
public function stickyAttributes()
{
- return array('baseControllerClass', 'indexWidgetType', 'enableSearch');
+ return array('baseControllerClass', 'moduleID', 'indexWidgetType', 'enableSearch');
+ }
+
+ public function validateModelClass()
+ {
+ /** @var ActiveRecord $class */
+ $class = $this->modelClass;
+ $pk = $class::primaryKey();
+ if (empty($pk)) {
+ $this->addError('modelClass', "The table associated with $class must have primary key(s).");
+ }
}
public function validateSearchModelClass()
@@ -116,6 +127,16 @@ class Generator extends \yii\gii\Generator
}
}
+ public function validateModuleID()
+ {
+ if (!empty($this->moduleID)) {
+ $module = Yii::$app->getModule($this->moduleID);
+ if ($module === null) {
+ $this->addError('moduleID', "Module '{$this->moduleID}' does not exist.");
+ }
+ }
+ }
+
/**
* @inheritdoc
*/
@@ -130,6 +151,9 @@ class Generator extends \yii\gii\Generator
$templatePath = $this->getTemplatePath() . '/views';
foreach (scandir($templatePath) as $file) {
+ if (!in_array($file, array('create.php', 'update.php', 'view.php'))) {
+ continue;
+ }
if (is_file($templatePath . '/' . $file) && pathinfo($file, PATHINFO_EXTENSION) === 'php') {
$files[] = new CodeFile("$viewPath/$file", $this->render("views/$file"));
}
@@ -142,39 +166,14 @@ class Generator extends \yii\gii\Generator
return $files;
}
-
- /**
- * @return string the controller class name without the namespace part.
- */
- public function getControllerClass()
- {
- return Inflector::id2camel($this->getControllerID()) . 'Controller';
- }
-
/**
* @return string the controller ID (without the module ID prefix)
*/
public function getControllerID()
{
- if (($pos = strrpos($this->controllerID, '/')) !== false) {
- return substr($this->controllerID, $pos + 1);
- } else {
- return $this->controllerID;
- }
- }
-
- /**
- * @return \yii\base\Module the module that the new controller belongs to
- */
- public function getModule()
- {
- if (($pos = strpos($this->controllerID, '/')) !== false) {
- $id = substr($this->controllerID, 0, $pos);
- if (($module = Yii::$app->getModule($id)) !== null) {
- return $module;
- }
- }
- return Yii::$app;
+ $pos = strrpos($this->controllerClass, '\\');
+ $class = substr(substr($this->controllerClass, $pos + 1), 0, -10);
+ return Inflector::camel2id($class);
}
/**
@@ -182,8 +181,7 @@ class Generator extends \yii\gii\Generator
*/
public function getControllerFile()
{
- $module = $this->getModule();
- return $module->getControllerPath() . '/' . $this->getControllerClass() . '.php';
+ return Yii::getAlias('@' . str_replace('\\', '/', ltrim($this->controllerClass, '\\')) . '.php');
}
/**
@@ -191,7 +189,20 @@ class Generator extends \yii\gii\Generator
*/
public function getViewPath()
{
- $module = $this->getModule();
+ $module = empty($this->moduleID) ? Yii::$app : Yii::$app->getModule($this->moduleID);
return $module->getViewPath() . '/' . $this->getControllerID() ;
}
+
+ public function getNameAttribute()
+ {
+ /** @var \yii\db\ActiveRecord $class */
+ $class = $this->modelClass;
+ foreach ($class::getTableSchema()->columnNames as $name) {
+ if (!strcasecmp($name, 'name') || !strcasecmp($name, 'title')) {
+ return $name;
+ }
+ }
+ $pk = $class::primaryKey();
+ return $pk[0];
+ }
}
diff --git a/framework/yii/gii/generators/crud/form.php b/framework/yii/gii/generators/crud/form.php
index 095791f..ee4771b 100644
--- a/framework/yii/gii/generators/crud/form.php
+++ b/framework/yii/gii/generators/crud/form.php
@@ -6,11 +6,12 @@
*/
echo $form->field($generator, 'modelClass');
-echo $form->field($generator, 'controllerID');
+echo $form->field($generator, 'controllerClass');
echo $form->field($generator, 'baseControllerClass');
+echo $form->field($generator, 'moduleID');
+echo $form->field($generator, 'enableSearch')->checkbox();
+echo $form->field($generator, 'searchModelClass');
echo $form->field($generator, 'indexWidgetType')->dropDownList(array(
'grid' => 'GridView',
'list' => 'ListView',
));
-echo $form->field($generator, 'enableSearch')->checkbox();
-echo $form->field($generator, 'searchModelClass');
diff --git a/framework/yii/gii/generators/crud/templates/controller.php b/framework/yii/gii/generators/crud/templates/controller.php
index 47c193f..7b3cce8 100644
--- a/framework/yii/gii/generators/crud/templates/controller.php
+++ b/framework/yii/gii/generators/crud/templates/controller.php
@@ -1,180 +1,152 @@
-
-
-class controllerClass; ?> extends baseControllerClass."\n"; ?>
-{
- /**
- * @var string the default layout for the views. Defaults to '//layouts/column2', meaning
- * using two-column layout. See 'protected/views/layouts/column2.php'.
- */
- public $layout='//layouts/column2';
- /**
- * @return array action filters
- */
- public function filters()
- {
- return array(
- 'accessControl', // perform access control for CRUD operations
- 'postOnly + delete', // we only allow deletion via POST request
- );
+$pos = strrpos($generator->controllerClass, '\\');
+$ns = ltrim(substr($generator->controllerClass, 0, $pos), '\\');
+$controllerClass = substr($generator->controllerClass, $pos + 1);
+$pos = strrpos($generator->modelClass, '\\');
+$modelClass = $pos === false ? $generator->modelClass : substr($generator->modelClass, $pos + 1);
+
+/** @var \yii\db\ActiveRecord $class */
+$class = $generator->modelClass;
+$pks = $class::primaryKey();
+$schema = $class::getTableSchema();
+if (count($pks) === 1) {
+ $ids = '$id';
+ $params = "array('id' => \$model->{$pks[0]})";
+ $paramComments = '@param ' . $schema->columns[$pks[0]]->phpType . ' $id';
+} else {
+ $ids = '$' . implode(', $', $pks);
+ $params = array();
+ $paramComments = array();
+ foreach ($pks as $pk) {
+ $paramComments[] = '@param ' . $schema->columns[$pk]->phpType . ' $' . $pk;
+ $params[] = "'$pk' => \$model->$pk";
}
+ $params = implode(', ', $params);
+ $paramComments = implode("\n\t * ", $paramComments);
+}
- /**
- * Specifies the access control rules.
- * This method is used by the 'accessControl' filter.
- * @return array access control rules
- */
- public function accessRules()
- {
- return array(
- array('allow', // allow all users to perform 'index' and 'view' actions
- 'actions'=>array('index','view'),
- 'users'=>array('*'),
- ),
- array('allow', // allow authenticated user to perform 'create' and 'update' actions
- 'actions'=>array('create','update'),
- 'users'=>array('@'),
- ),
- array('allow', // allow admin user to perform 'admin' and 'delete' actions
- 'actions'=>array('admin','delete'),
- 'users'=>array('admin'),
- ),
- array('deny', // deny all users
- 'users'=>array('*'),
- ),
- );
- }
+echo "
+
+namespace ;
+
+use modelClass, '\\'); ?>;
+use yii\data\ActiveDataProvider;
+use baseControllerClass, '\\'); ?>;
+use yii\web\HttpException;
+/**
+ * implements the CRUD actions for model.
+ */
+class extends baseControllerClass) . "\n"; ?>
+{
/**
- * Displays a particular model.
- * @param integer $id the ID of the model to be displayed
+ * Displays a single model.
+ *
+ * @return mixed
*/
- public function actionView($id)
+ public function actionView()
{
- $this->render('view',array(
- 'model'=>$this->loadModel($id),
+ return $this->render('view', array(
+ 'model' => $this->findModel(),
));
}
/**
- * Creates a new model.
+ * Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
*/
public function actionCreate()
{
- $model=new modelClass; ?>;
-
- // Uncomment the following line if AJAX validation is needed
- // $this->performAjaxValidation($model);
-
- if(isset($_POST['modelClass; ?>']))
- {
- $model->attributes=$_POST['modelClass; ?>'];
- if($model->save())
- $this->redirect(array('view','id'=>$model->tableSchema->primaryKey; ?>));
+ $model = new ;
+
+ if ($model->load($_POST) && $model->save()) {
+ return $this->redirect(array('view', ));
+ } else {
+ return $this->render('create', array(
+ 'model' => $model,
+ ));
}
-
- $this->render('create',array(
- 'model'=>$model,
- ));
}
/**
- * Updates a particular model.
+ * Updates an existing model.
* If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id the ID of the model to be updated
+ *
+ * @return mixed
*/
- public function actionUpdate($id)
+ public function actionUpdate()
{
- $model=$this->loadModel($id);
-
- // Uncomment the following line if AJAX validation is needed
- // $this->performAjaxValidation($model);
-
- if(isset($_POST['modelClass; ?>']))
- {
- $model->attributes=$_POST['modelClass; ?>'];
- if($model->save())
- $this->redirect(array('view','id'=>$model->tableSchema->primaryKey; ?>));
+ $model = $this->findModel();
+
+ if ($model->load($_POST) && $model->save()) {
+ return $this->redirect(array('view', ));
+ } else {
+ return $this->render('update', array(
+ 'model' => $model,
+ ));
}
-
- $this->render('update',array(
- 'model'=>$model,
- ));
}
/**
- * Deletes a particular model.
- * If deletion is successful, the browser will be redirected to the 'admin' page.
- * @param integer $id the ID of the model to be deleted
+ * Deletes an existing model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ *
+ * @return mixed
*/
- public function actionDelete($id)
+ public function actionDelete()
{
- $this->loadModel($id)->delete();
-
- // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
- if(!isset($_GET['ajax']))
- $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
+ $this->findModel()->delete();
+ return $this->redirect(array('index'));
}
/**
* Lists all models.
+ * @return mixed
*/
public function actionIndex()
{
- $dataProvider=new CActiveDataProvider('modelClass; ?>');
- $this->render('index',array(
- 'dataProvider'=>$dataProvider,
+ $dataProvider = new ActiveDataProvider('');
+ return $this->render('index', array(
+ 'dataProvider' => $dataProvider,
));
}
/**
- * Manages all models.
+ * Returns the data model based on its primary key value.
+ * If the data model is not found, a 404 HTTP exception will be thrown.
+ *
+ * @return the loaded model
+ * @throws HttpException if the model cannot be found
*/
- public function actionAdmin()
+ protected function findModel()
{
- $model=new modelClass; ?>('search');
- $model->unsetAttributes(); // clear any default values
- if(isset($_GET['modelClass; ?>']))
- $model->attributes=$_GET['modelClass; ?>'];
-
- $this->render('admin',array(
- 'model'=>$model,
- ));
- }
-
- /**
- * Returns the data model based on the primary key given in the GET variable.
- * If the data model is not found, an HTTP exception will be raised.
- * @param integer $id the ID of the model to be loaded
- * @return modelClass; ?> the loaded model
- * @throws CHttpException
- */
- public function loadModel($id)
- {
- $model=modelClass; ?>::model()->findByPk($id);
- if($model===null)
- throw new CHttpException(404,'The requested page does not exist.');
- return $model;
+ \$$pk";
}
-
- /**
- * Performs the AJAX validation.
- * @param modelClass; ?> $model the model to be validated
- */
- protected function performAjaxValidation($model)
- {
- if(isset($_POST['ajax']) && $_POST['ajax']==='class2id($this->modelClass); ?>-form')
- {
- echo CActiveForm::validate($model);
- Yii::app()->end();
+ $condition = 'array(' . implode(', ', $condition) . ')';
+}
+?>
+ $model = ::find();
+ if ($model === null) {
+ throw new HttpException(404, 'The requested page does not exist.');
}
+ return $model;
}
}
diff --git a/framework/yii/gii/generators/crud/templates/views/create.php b/framework/yii/gii/generators/crud/templates/views/create.php
index 9fd3ccf..48a2318 100644
--- a/framework/yii/gii/generators/crud/templates/views/create.php
+++ b/framework/yii/gii/generators/crud/templates/views/create.php
@@ -1,27 +1,31 @@
-
-/* @var $this getControllerClass(); ?> */
-/* @var $model getModelClass(); ?> */
-pluralize($this->class2name($this->modelClass));
-echo "\$this->breadcrumbs=array(
- '$label'=>array('index'),
- 'Create',
-);\n";
+echo "
-$this->menu=array(
- array('label'=>'List modelClass; ?>', 'url'=>array('index')),
- array('label'=>'Manage modelClass; ?>', 'url'=>array('admin')),
-);
+use yii\helpers\Html;
+
+/**
+ * @var yii\base\View $this
+ * @var modelClass, '\\'); ?> $model
+ */
+
+$this->title = 'Create modelClass)); ?>';
?>
+