Generator.php 6.41 KB
Newer Older
Qiang Xue committed
1 2 3 4 5 6 7 8 9
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\gii\generators\crud;

Qiang Xue committed
10
use Yii;
Qiang Xue committed
11
use yii\base\Model;
Qiang Xue committed
12 13
use yii\db\ActiveRecord;
use yii\gii\CodeFile;
Qiang Xue committed
14
use yii\helpers\Inflector;
Qiang Xue committed
15 16
use yii\web\Controller;

Qiang Xue committed
17 18 19 20 21 22 23
/**
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Generator extends \yii\gii\Generator
{
Qiang Xue committed
24
	public $modelClass;
Qiang Xue committed
25 26
	public $moduleID;
	public $controllerClass;
Qiang Xue committed
27
	public $baseControllerClass = 'yii\web\Controller';
Qiang Xue committed
28 29 30
	public $indexWidgetType = 'grid';
	public $enableSearch = true;
	public $searchModelClass;
Qiang Xue committed
31

Qiang Xue committed
32 33 34 35 36 37 38 39 40 41
	public function getName()
	{
		return 'CRUD Generator';
	}

	public function getDescription()
	{
		return 'This generator generates a controller and views that implement CRUD (Create, Read, Update, Delete)
			operations for the specified data model.';
	}
42

Qiang Xue committed
43 44 45
	public function rules()
	{
		return array_merge(parent::rules(), array(
Qiang Xue committed
46 47 48
			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.'),
Qiang Xue committed
49 50
			array('modelClass', 'validateClass', 'params' => array('extends' => ActiveRecord::className())),
			array('baseControllerClass', 'validateClass', 'params' => array('extends' => Controller::className())),
Qiang Xue committed
51 52
			array('controllerClass', 'match', 'pattern' => '/Controller$/', 'message' => 'Controller class name must be suffixed with "Controller".'),
			array('controllerClass, searchModelClass', 'validateNewClass'),
Qiang Xue committed
53 54
			array('enableSearch', 'boolean'),
			array('indexWidgetType', 'in', 'range' => array('grid', 'list')),
Qiang Xue committed
55
			array('modelClass', 'validateModelClass'),
Qiang Xue committed
56
			array('searchModelClass', 'validateSearchModelClass'),
Qiang Xue committed
57
			array('moduleID', 'validateModuleID'),
Qiang Xue committed
58 59 60 61 62 63 64
		));
	}

	public function attributeLabels()
	{
		return array_merge(parent::attributeLabels(), array(
			'modelClass' => 'Model Class',
Qiang Xue committed
65 66
			'moduleID' => 'Module ID',
			'controllerClass' => 'Controller Class',
Qiang Xue committed
67
			'baseControllerClass' => 'Base Controller Class',
Qiang Xue committed
68 69 70
			'indexWidgetType' => 'Widget Used in Index Page',
			'enableSearch' => 'Enable Search',
			'searchModelClass' => 'Search Model Class',
Qiang Xue committed
71 72 73 74 75 76 77 78 79 80 81
		));
	}

	/**
	 * @inheritdoc
	 */
	public function hints()
	{
		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., <code>app\models\Post</code>.',
Qiang Xue committed
82 83
			'controllerClass' => 'This is the name of the controller class to be generated. You should
				provide a fully qualified namespaced class, .e.g, <code>app\controllers\PostController</code>.',
Qiang Xue committed
84 85
			'baseControllerClass' => 'This is the class that the new CRUD controller class will extend from.
				You should provide a fully qualified class name, e.g., <code>yii\web\Controller</code>.',
Qiang Xue committed
86 87
			'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.',
Qiang Xue committed
88 89 90 91 92 93 94
			'indexWidgetType' => 'This is the widget type to be used in the index page to display list of the models.
				You may choose either <code>GridView</code> or <code>ListView</code>',
			'enableSearch' => 'Whether to enable the search functionality on the index page. When search is enabled,
				a search form will be displayed on the index page, and the index page will display the search results.',
			'searchModelClass' => 'This is the class representing the data being collecting in the search form.
			 	A fully qualified namespaced class name is required, e.g., <code>app\models\PostSearchForm</code>.
				This is only used when search is enabled.',
Qiang Xue committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
		);
	}

	public function requiredTemplates()
	{
		return array(
			'controller.php',
		);
	}

	/**
	 * @inheritdoc
	 */
	public function stickyAttributes()
	{
Qiang Xue committed
110 111 112 113 114 115 116 117 118 119 120
		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).");
		}
Qiang Xue committed
121 122
	}

Qiang Xue committed
123 124 125 126 127 128 129
	public function validateSearchModelClass()
	{
		if ($this->enableSearch && empty($this->searchModelClass)) {
			$this->addError('searchModelClass', 'Search Model Class cannot be empty.');
		}
	}

Qiang Xue committed
130 131 132 133 134 135 136 137 138 139
	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.");
			}
		}
	}

140 141 142 143 144
	/**
	 * @inheritdoc
	 */
	public function generate()
	{
Qiang Xue committed
145 146
		$files = array();
		$files[] = new CodeFile(
Qiang Xue committed
147
			$this->getControllerFile(),
Qiang Xue committed
148 149
			$this->render('controller.php')
		);
Qiang Xue committed
150
		$viewPath = $this->getViewPath();
Qiang Xue committed
151

Qiang Xue committed
152 153
		$templatePath = $this->getTemplatePath() . '/views';
		foreach (scandir($templatePath) as $file) {
Qiang Xue committed
154 155 156
			if (!in_array($file, array('create.php', 'update.php', 'view.php'))) {
				continue;
			}
Qiang Xue committed
157 158
			if (is_file($templatePath . '/' . $file) && pathinfo($file, PATHINFO_EXTENSION) === 'php') {
				$files[] = new CodeFile("$viewPath/$file", $this->render("views/$file"));
Qiang Xue committed
159 160 161
			}
		}

Qiang Xue committed
162 163 164 165
		if ($this->enableSearch) {

		}

Qiang Xue committed
166
		return $files;
167
	}
Qiang Xue committed
168 169 170 171 172 173

	/**
	 * @return string the controller ID (without the module ID prefix)
	 */
	public function getControllerID()
	{
Qiang Xue committed
174 175 176
		$pos = strrpos($this->controllerClass, '\\');
		$class = substr(substr($this->controllerClass, $pos + 1), 0, -10);
		return Inflector::camel2id($class);
Qiang Xue committed
177 178 179 180 181 182 183
	}

	/**
	 * @return string the controller class file path
	 */
	public function getControllerFile()
	{
Qiang Xue committed
184
		return Yii::getAlias('@' . str_replace('\\', '/', ltrim($this->controllerClass, '\\')) . '.php');
Qiang Xue committed
185 186 187 188 189 190 191
	}

	/**
	 * @return string the action view file path
	 */
	public function getViewPath()
	{
Qiang Xue committed
192
		$module = empty($this->moduleID) ? Yii::$app : Yii::$app->getModule($this->moduleID);
Qiang Xue committed
193 194
		return $module->getViewPath() . '/' . $this->getControllerID() ;
	}
Qiang Xue committed
195 196 197 198 199 200 201 202 203 204 205 206 207

	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];
	}
Qiang Xue committed
208
}