Generator.php 4.5 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\form;

Qiang Xue committed
10 11 12 13
use Yii;
use yii\base\Model;
use yii\gii\CodeFile;

Qiang Xue committed
14
/**
15
 * This generator will generate an action view file based on the specified model class.
Qiang Xue committed
16 17 18 19 20 21
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Generator extends \yii\gii\Generator
{
Qiang Xue committed
22 23 24
	public $modelClass;
	public $viewPath = '@app/views';
	public $viewName;
Qiang Xue committed
25
	public $scenarioName;
Qiang Xue committed
26 27 28 29 30


	/**
	 * @inheritdoc
	 */
Qiang Xue committed
31 32 33 34 35
	public function getName()
	{
		return 'Form Generator';
	}

Qiang Xue committed
36 37 38
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
39 40 41 42
	public function getDescription()
	{
		return 'This generator generates a view script file that displays a form to collect input for the specified model class.';
	}
43 44 45 46 47 48

	/**
	 * @inheritdoc
	 */
	public function generate()
	{
Qiang Xue committed
49 50 51
		$files = array();
		$files[] = new CodeFile(
			Yii::getAlias($this->viewPath) . '/' . $this->viewName . '.php',
Qiang Xue committed
52
			$this->render('form.php')
Qiang Xue committed
53 54 55 56
		);
		return $files;
	}

Qiang Xue committed
57 58 59
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
60 61 62
	public function rules()
	{
		return array_merge(parent::rules(), array(
Qiang Xue committed
63
			array('modelClass, viewName, scenarioName, viewPath', 'filter', 'filter' => 'trim'),
Qiang Xue committed
64
			array('modelClass, viewName, viewPath', 'required'),
Qiang Xue committed
65
			array('modelClass', 'match', 'pattern' => '/^[\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'),
Qiang Xue committed
66
			array('modelClass', 'validateModel'),
Qiang Xue committed
67 68
			array('viewName', 'match', 'pattern' => '/^\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes and slashes are allowed.'),
			array('viewPath', 'match', 'pattern' => '/^@?\w+[\\-\\/\w]*$/', 'message' => 'Only word characters, dashes, slashes and @ are allowed.'),
Qiang Xue committed
69
			array('viewPath', 'validateViewPath'),
Qiang Xue committed
70
			array('scenarioName', 'match', 'pattern' => '/^[\w\\-]+$/', 'message' => 'Only word characters and dashes are allowed.'),
Qiang Xue committed
71 72 73
		));
	}

Qiang Xue committed
74 75 76
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
77 78 79 80 81 82 83 84 85 86
	public function attributeLabels()
	{
		return array(
			'modelClass' => 'Model Class',
			'viewName' => 'View Name',
			'viewPath' => 'View Path',
			'scenarioName' => 'Scenario',
		);
	}

Qiang Xue committed
87 88 89
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
	public function requiredTemplates()
	{
		return array(
			'form.php',
			'action.php',
		);
	}

	/**
	 * @inheritdoc
	 */
	public function stickyAttributes()
	{
		return array('viewPath', 'scenarioName');
	}

	/**
	 * @inheritdoc
	 */
	public function hints()
	{
		return array(
Qiang Xue committed
112 113 114 115
			'modelClass' => 'This is the model class for collecting the form input. You should provide a fully qualified class name, e.g., <code>app\models\Post</code>.',
			'viewName' => 'This is the view name with respect to the view path. For example, <code>site/index</code> would generate a <code>site/index.php</code> view file under the view path.',
			'viewPath' => 'This is the root view path to keep the generated view files. You may provide either a directory or a path alias, e.g., <code>@app/views</code>.',
			'scenarioName' => 'This is the scenario to be used by the model when collecting the form input. If empty, the default scenario will be used.',
Qiang Xue committed
116 117 118
		);
	}

Qiang Xue committed
119 120 121
	/**
	 * @inheritdoc
	 */
Qiang Xue committed
122 123
	public function successMessage()
	{
Qiang Xue committed
124
		$code = highlight_string($this->render('action.php'), true);
Qiang Xue committed
125
		return <<<EOD
Qiang Xue committed
126 127
<p>The form has been generated successfully.</p>
<p>You may add the following code in an appropriate controller class to invoke the view:</p>
128
<pre>$code</pre>
Qiang Xue committed
129 130 131
EOD;
	}

Qiang Xue committed
132 133 134 135
	/**
	 * Validates the model class to make sure it exists and is valid.
	 */
	public function validateModel()
Qiang Xue committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
	{
		try {
			if (class_exists($this->modelClass)) {
				if (!is_subclass_of($this->modelClass, Model::className())) {
					$this->addError('modelClass', "'{$this->modelClass}' must extend from Model or its child class.");
				}
			} else {
				$this->addError('modelClass', "Class '{$this->modelClass}' does not exist or has syntax error.");
			}
		} catch (\Exception $e) {
			$this->addError('modelClass', "Class '{$this->modelClass}' does not exist or has syntax error.");
			return;
		}
	}

Qiang Xue committed
151 152 153
	/**
	 * Validates [[viewPath]] to make sure it is a valid path or path alias and exists.
	 */
Qiang Xue committed
154 155 156 157 158 159 160 161
	public function validateViewPath()
	{
		$path = Yii::getAlias($this->viewPath, false);
		if ($path === false || !is_dir($path)) {
			$this->addError('viewPath', 'View path does not exist.');
		}
	}

Qiang Xue committed
162 163 164
	/**
	 * @return array list of safe attributes of [[modelClass]]
	 */
Qiang Xue committed
165 166 167 168
	public function getModelAttributes()
	{
		/** @var Model $model */
		$model = new $this->modelClass;
Qiang Xue committed
169 170 171
		if (!empty($this->scenarioName)) {
			$model->setScenario($this->scenarioName);
		}
Qiang Xue committed
172
		return $model->safeAttributes();
173
	}
Qiang Xue committed
174
}