diff --git a/apps/advanced/backend/views/site/login.php b/apps/advanced/backend/views/site/login.php index b37bb6b..0c16570 100644 --- a/apps/advanced/backend/views/site/login.php +++ b/apps/advanced/backend/views/site/login.php @@ -21,7 +21,7 @@ $this->params['breadcrumbs'][] = $this->title; field($model, 'username'); ?> field($model, 'password')->passwordInput(); ?> field($model, 'rememberMe')->checkbox(); ?> -
+
'btn btn-primary')); ?>
diff --git a/apps/advanced/frontend/views/site/contact.php b/apps/advanced/frontend/views/site/contact.php index f3addf0..851deda 100644 --- a/apps/advanced/frontend/views/site/contact.php +++ b/apps/advanced/frontend/views/site/contact.php @@ -29,7 +29,7 @@ $this->params['breadcrumbs'][] = $this->title; 'options' => array('class' => 'form-control'), 'template' => '
{image}
{input}
', )); ?> -
+
'btn btn-primary')); ?>
diff --git a/apps/advanced/frontend/views/site/login.php b/apps/advanced/frontend/views/site/login.php index 6e8020f..5e7f6f6 100644 --- a/apps/advanced/frontend/views/site/login.php +++ b/apps/advanced/frontend/views/site/login.php @@ -24,7 +24,7 @@ $this->params['breadcrumbs'][] = $this->title;
If you forgot your password you can .
-
+
'btn btn-primary')); ?>
diff --git a/apps/advanced/frontend/views/site/requestPasswordResetToken.php b/apps/advanced/frontend/views/site/requestPasswordResetToken.php index 88170d3..c754948 100644 --- a/apps/advanced/frontend/views/site/requestPasswordResetToken.php +++ b/apps/advanced/frontend/views/site/requestPasswordResetToken.php @@ -19,7 +19,7 @@ $this->params['breadcrumbs'][] = $this->title;
'request-password-reset-form')); ?> field($model, 'email'); ?> -
+
'btn btn-primary')); ?>
diff --git a/apps/advanced/frontend/views/site/resetPassword.php b/apps/advanced/frontend/views/site/resetPassword.php index 0d7223e..2c38028 100644 --- a/apps/advanced/frontend/views/site/resetPassword.php +++ b/apps/advanced/frontend/views/site/resetPassword.php @@ -19,10 +19,10 @@ $this->params['breadcrumbs'][] = $this->title;
'reset-password-form')); ?> field($model, 'password')->passwordInput(); ?> -
+
'btn btn-primary')); ?>
-
\ No newline at end of file +
diff --git a/apps/advanced/frontend/views/site/signup.php b/apps/advanced/frontend/views/site/signup.php index e4b8cec..92525bf 100644 --- a/apps/advanced/frontend/views/site/signup.php +++ b/apps/advanced/frontend/views/site/signup.php @@ -21,7 +21,7 @@ $this->params['breadcrumbs'][] = $this->title; field($model, 'username'); ?> field($model, 'email'); ?> field($model, 'password')->passwordInput(); ?> -
+
'btn btn-primary')); ?>
diff --git a/apps/basic/views/site/contact.php b/apps/basic/views/site/contact.php index e08c9ae..d1411c0 100644 --- a/apps/basic/views/site/contact.php +++ b/apps/basic/views/site/contact.php @@ -37,7 +37,7 @@ $this->params['breadcrumbs'][] = $this->title; 'options' => array('class' => 'form-control'), 'template' => '
{image}
{input}
', )); ?> -
+
'btn btn-primary')); ?>
diff --git a/apps/basic/views/site/login.php b/apps/basic/views/site/login.php index b00ecf4..524b0cc 100644 --- a/apps/basic/views/site/login.php +++ b/apps/basic/views/site/login.php @@ -21,7 +21,7 @@ $this->params['breadcrumbs'][] = $this->title; field($model, 'username'); ?> field($model, 'password')->passwordInput(); ?> field($model, 'rememberMe')->checkbox(); ?> -
+
'btn btn-primary')); ?>
diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index 15a00c7..88735e0 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -338,7 +338,7 @@ It is represented as an `ActiveField` object. Using fields, you can build a form field($model, 'username'); ?> field($model, 'password')->passwordInput(); ?> -
+
diff --git a/framework/yii/gii/CodeFile.php b/framework/yii/gii/CodeFile.php new file mode 100644 index 0000000..bb42294 --- /dev/null +++ b/framework/yii/gii/CodeFile.php @@ -0,0 +1,127 @@ + + * @since 2.0 + */ +class CodeFile extends Object +{ + const OP_NEW = 'new'; + const OP_OVERWRITE = 'overwrite'; + const OP_SKIP = 'skip'; + + /** + * @var string the file path that the new code should be saved to. + */ + public $path; + /** + * @var mixed the newly generated code. If this is null, it means {@link path} + * should be treated as a directory. + */ + public $content; + /** + * @var string the operation to be performed + */ + public $operation; + /** + * @var string the error occurred when saving the code into a file + */ + public $error; + + /** + * Constructor. + * @param string $path the file path that the new code should be saved to. + * @param string $content the newly generated code + */ + public function __construct($path, $content) + { + $this->path = strtr($path, array('/' => DIRECTORY_SEPARATOR, '\\' => DIRECTORY_SEPARATOR)); + $this->content = $content; + if (is_file($path)) { + $this->operation = file_get_contents($path) === $content ? self::OP_SKIP : self::OP_OVERWRITE; + } elseif ($content === null) // is dir + { + $this->operation = is_dir($path) ? self::OP_SKIP : self::OP_NEW; + } else { + $this->operation = self::OP_NEW; + } + } + + /** + * Saves the code into the file {@link path}. + */ + public function save() + { + $module = Yii::$app->controller->module; + if ($this->content === null) // a directory + { + if (!is_dir($this->path)) { + $oldmask = @umask(0); + $result = @mkdir($this->path, $module->newDirMode, true); + @umask($oldmask); + if (!$result) { + $this->error = "Unable to create the directory '{$this->path}'."; + return false; + } + } + return true; + } + + if ($this->operation === self::OP_NEW) { + $dir = dirname($this->path); + if (!is_dir($dir)) { + $oldmask = @umask(0); + $result = @mkdir($dir, $module->newDirMode, true); + @umask($oldmask); + if (!$result) { + $this->error = "Unable to create the directory '$dir'."; + return false; + } + } + } + if (@file_put_contents($this->path, $this->content) === false) { + $this->error = "Unable to write the file '{$this->path}'."; + return false; + } else { + $oldmask = @umask(0); + @chmod($this->path, $module->newFileMode); + @umask($oldmask); + } + return true; + } + + /** + * @return string the code file path relative to the application base path. + */ + public function getRelativePath() + { + if (strpos($this->path, Yii::$app->basePath) === 0) { + return substr($this->path, strlen(Yii::$app->basePath) + 1); + } else { + return $this->path; + } + } + + /** + * @return string the code file extension (e.g. php, txt) + */ + public function getType() + { + if (($pos = strrpos($this->path, '.')) !== false) { + return substr($this->path, $pos + 1); + } else { + return 'unknown'; + } + } +} diff --git a/framework/yii/gii/Generator.php b/framework/yii/gii/Generator.php index 5e7b1f0..13b7c54 100644 --- a/framework/yii/gii/Generator.php +++ b/framework/yii/gii/Generator.php @@ -8,161 +8,73 @@ namespace yii\gii; use Yii; +use ReflectionClass; +use yii\base\InvalidConfigException; use yii\base\Model; +use yii\base\View; /** * @author Qiang Xue * @since 2.0 */ -class Generator extends Model +abstract class Generator extends Model { + public $templates = array(); /** - * @var string + * @var string the name of the code template that the user has selected. + * The value of this property is internally managed by this class and {@link CCodeGenerator}. */ - public $id; + public $template; /** * @return string name of the code generator */ - public function getName() + abstract public function getName(); + + public function init() { - return 'unknown'; + parent::init(); + if (!isset($this->templates['default'])) { + $this->templates['default'] = $this->getDefaultTemplate(); + } } - public function getDescription() + /** + * Prepares the code files to be generated. + * This is the main method that child classes should implement. It should contain the logic + * that populates the {@link files} property with a list of code files to be generated. + */ + public function prepare() { - return ''; + return array(); } - public function getUrl() + /** + * Returns a list of code templates that are required. + * Derived classes usually should override this method. + * @return array list of code templates that are required. They should be file paths + * relative to {@link templatePath}. + */ + public function requiredTemplates() { - return Yii::$app->controller->createUrl('default/view', array('id' => $this->id)); + return array(); } - public function renderForm() + public function getViewFile() { - return ''; + $class = new ReflectionClass($this); + return dirname($class->getFileName()) . '/views/form.php'; } - public function renderFileList() + public function getDefaultTemplate() { - return ''; + $class = new ReflectionClass($this); + return dirname($class->getFileName()) . '/templates'; } - const STATUS_NEW = 1; - const STATUS_PREVIEW = 2; - const STATUS_SUCCESS = 3; - const STATUS_ERROR = 4; - - static $keywords = array( - '__class__', - '__dir__', - '__file__', - '__function__', - '__line__', - '__method__', - '__namespace__', - 'abstract', - 'and', - 'array', - 'as', - 'break', - 'case', - 'catch', - 'cfunction', - 'class', - 'clone', - 'const', - 'continue', - 'declare', - 'default', - 'die', - 'do', - 'echo', - 'else', - 'elseif', - 'empty', - 'enddeclare', - 'endfor', - 'endforeach', - 'endif', - 'endswitch', - 'endwhile', - 'eval', - 'exception', - 'exit', - 'extends', - 'final', - 'final', - 'for', - 'foreach', - 'function', - 'global', - 'goto', - 'if', - 'implements', - 'include', - 'include_once', - 'instanceof', - 'interface', - 'isset', - 'list', - 'namespace', - 'new', - 'old_function', - 'or', - 'parent', - 'php_user_filter', - 'print', - 'private', - 'protected', - 'public', - 'require', - 'require_once', - 'return', - 'static', - 'switch', - 'this', - 'throw', - 'try', - 'unset', - 'use', - 'var', - 'while', - 'xor', - ); - - /** - * @var array user confirmations on whether to overwrite existing code files with the newly generated ones. - * The value of this property is internally managed by this class and {@link CCodeGenerator}. - */ - public $answers; - /** - * @var string the name of the code template that the user has selected. - * The value of this property is internally managed by this class and {@link CCodeGenerator}. - */ - public $template; - /** - * @var array a list of {@link CCodeFile} objects that represent the code files to be generated. - * The {@link prepare()} method is responsible to populate this property. - */ - public $files = array(); - /** - * @var integer the status of this model. T - * The value of this property is internally managed by {@link CCodeGenerator}. - */ - public $status = self::STATUS_NEW; - - private $_stickyAttributes = array(); - - /** - * Prepares the code files to be generated. - * This is the main method that child classes should implement. It should contain the logic - * that populates the {@link files} property with a list of code files to be generated. - */ - public function prepare() + public function getDescription() { - + return ''; } /** @@ -178,35 +90,12 @@ class Generator extends Model public function rules() { return array( - array('template', 'required'), + array('template', 'required', 'message' => 'A code template must be selected.'), array('template', 'validateTemplate', 'skipOnError' => true), - array('template', 'sticky'), ); } /** - * Validates the template selection. - * This method validates whether the user selects an existing template - * and the template contains all required template files as specified in {@link requiredTemplates}. - * @param string $attribute the attribute to be validated - * @param array $params validation parameters - */ - public function validateTemplate($attribute, $params) - { - $templates = $this->templates; - if (!isset($templates[$this->template])) { - $this->addError('template', 'Invalid template selection.'); - } else { - $templatePath = $this->templatePath; - foreach ($this->requiredTemplates() as $template) { - if (!is_file($templatePath . '/' . $template)) { - $this->addError('template', "Unable to find the required code template file '$template'."); - } - } - } - } - - /** * Checks if the named class exists (in a case sensitive manner). * @param string $name class name to be checked * @return boolean whether the class exists @@ -217,40 +106,12 @@ class Generator extends Model } /** - * Declares the model attribute labels. - * Child classes must override this method in the following format: - *
-	 * return array_merge(parent::attributeLabels(), array(
-	 *     ...labels for the child class attributes...
-	 * ));
-	 * 
- * @return array the attribute labels - */ - public function attributeLabels() - { - return array( - 'template' => 'Code Template', - ); - } - - /** - * Returns a list of code templates that are required. - * Derived classes usually should override this method. - * @return array list of code templates that are required. They should be file paths - * relative to {@link templatePath}. - */ - public function requiredTemplates() - { - return array(); - } - - /** * Saves the generated code into files. */ - public function save() + public function save($files, $answers = array()) { $result = true; - foreach ($this->files as $file) { + foreach ($files as $file) { if ($this->confirmed($file)) { $result = $file->save() && $result; } @@ -259,59 +120,25 @@ class Generator extends Model } /** - * Returns the message to be displayed when the newly generated code is saved successfully. - * Child classes should override this method if the message needs to be customized. - * @return string the message to be displayed when the newly generated code is saved successfully. - */ - public function successMessage() - { - return 'The code has been generated successfully.'; - } - - /** - * Returns the message to be displayed when some error occurred during code file saving. - * Child classes should override this method if the message needs to be customized. - * @return string the message to be displayed when some error occurred during code file saving. - */ - public function errorMessage() - { - return 'There was some error when generating the code. Please check the following messages.'; - } - - /** - * Returns a list of available code templates (name=>directory). - * This method simply returns the {@link CCodeGenerator::templates} property value. - * @return array a list of available code templates (name=>directory). - */ - public function getTemplates() - { - return Yii::app()->controller->templates; - } - - /** * @return string the directory that contains the template files. - * @throws CHttpException if {@link templates} is empty or template selection is invalid + * @throws InvalidConfigException if {@link templates} is empty or template selection is invalid */ public function getTemplatePath() { - $templates = $this->getTemplates(); - if (isset($templates[$this->template])) { - return $templates[$this->template]; - } elseif (empty($templates)) { - throw new CHttpException(500, 'No templates are available.'); + if (isset($this->templates[$this->template])) { + return $this->templates[$this->template]; } else { - throw new CHttpException(500, 'Invalid template selection.'); + throw new InvalidConfigException("Unknown template: {$this->template}"); } - } /** - * @param CCodeFile $file whether the code file should be saved + * @param CodeFile $file whether the code file should be saved * @return bool whether the confirmation is found in {@link answers} with appropriate {@link operation} */ public function confirmed($file) { - return $this->answers === null && $file->operation === CCodeFile::OP_NEW + return $this->answers === null && $file->operation === CodeFile::OP_NEW || is_array($this->answers) && isset($this->answers[md5($file->path)]); } @@ -320,24 +147,12 @@ class Generator extends Model * This method is manly used in {@link generate} to generate code. * @param string $templateFile the code template file path * @param array $_params_ a set of parameters to be extracted and made available in the code template - * @throws CException is template file does not exist * @return string the generated code */ - public function render($templateFile, $_params_ = null) + public function render($templateFile, $params = array()) { - if (!is_file($templateFile)) { - throw new CException("The template file '$templateFile' does not exist."); - } - - if (is_array($_params_)) { - extract($_params_, EXTR_PREFIX_SAME, 'params'); - } else { - $params = $_params_; - } - ob_start(); - ob_implicit_flush(false); - require($templateFile); - return ob_get_clean(); + $view = new View; + return $view->renderFile($templateFile, $params, $this); } /** @@ -349,9 +164,9 @@ class Generator extends Model foreach ($this->files as $file) { if ($file->error !== null) { $output .= "generating {$file->relativePath}
{$file->error}
\n"; - } elseif ($file->operation === CCodeFile::OP_NEW && $this->confirmed($file)) { + } elseif ($file->operation === CodeFile::OP_NEW && $this->confirmed($file)) { $output .= ' generated ' . $file->relativePath . "\n"; - } elseif ($file->operation === CCodeFile::OP_OVERWRITE && $this->confirmed($file)) { + } elseif ($file->operation === CodeFile::OP_OVERWRITE && $this->confirmed($file)) { $output .= ' overwrote ' . $file->relativePath . "\n"; } else { $output .= ' skipped ' . $file->relativePath . "\n"; @@ -362,66 +177,111 @@ class Generator extends Model } /** - * The "sticky" validator. - * This validator does not really validate the attributes. - * It actually saves the attribute value in a file to make it sticky. - * @param string $attribute the attribute to be validated - * @param array $params the validation parameters - */ - public function sticky($attribute, $params) - { - if (!$this->hasErrors()) { - $this->_stickyAttributes[$attribute] = $this->$attribute; - } - } - - /** - * Loads sticky attributes from a file and populates them into the model. + * Validates the template selection. + * This method validates whether the user selects an existing template + * and the template contains all required template files as specified in {@link requiredTemplates}. */ - public function loadStickyAttributes() + public function validateTemplate() { - $this->_stickyAttributes = array(); - $path = $this->getStickyFile(); - if (is_file($path)) { - $result = @include($path); - if (is_array($result)) { - $this->_stickyAttributes = $result; - foreach ($this->_stickyAttributes as $name => $value) { - if (property_exists($this, $name) || $this->canSetProperty($name)) { - $this->$name = $value; - } + $templates = $this->templates; + if (!isset($templates[$this->template])) { + $this->addError('template', 'Invalid template selection.'); + } else { + $templatePath = $this->templates[$this->template]; + foreach ($this->requiredTemplates() as $template) { + if (!is_file($templatePath . '/' . $template)) { + $this->addError('template', "Unable to find the required code template file '$template'."); } } } } /** - * Saves sticky attributes into a file. - */ - public function saveStickyAttributes() - { - $path = $this->getStickyFile(); - @mkdir(dirname($path), 0755, true); - file_put_contents($path, "_stickyAttributes, true) . ";\n"); - } - - /** - * @return string the file path that stores the sticky attribute values. - */ - public function getStickyFile() - { - return Yii::app()->runtimePath . '/gii-' . Yii::getVersion() . '/' . get_class($this) . '.php'; - } - - /** * Validates an attribute to make sure it is not taking a PHP reserved keyword. * @param string $attribute the attribute to be validated * @param array $params validation parameters */ public function validateReservedWord($attribute, $params) { + static $keywords = array( + '__class__', + '__dir__', + '__file__', + '__function__', + '__line__', + '__method__', + '__namespace__', + 'abstract', + 'and', + 'array', + 'as', + 'break', + 'case', + 'catch', + 'cfunction', + 'class', + 'clone', + 'const', + 'continue', + 'declare', + 'default', + 'die', + 'do', + 'echo', + 'else', + 'elseif', + 'empty', + 'enddeclare', + 'endfor', + 'endforeach', + 'endif', + 'endswitch', + 'endwhile', + 'eval', + 'exception', + 'exit', + 'extends', + 'final', + 'final', + 'for', + 'foreach', + 'function', + 'global', + 'goto', + 'if', + 'implements', + 'include', + 'include_once', + 'instanceof', + 'interface', + 'isset', + 'list', + 'namespace', + 'new', + 'old_function', + 'or', + 'parent', + 'php_user_filter', + 'print', + 'private', + 'protected', + 'public', + 'require', + 'require_once', + 'return', + 'static', + 'switch', + 'this', + 'throw', + 'try', + 'unset', + 'use', + 'var', + 'while', + 'xor', + ); $value = $this->$attribute; - if (in_array(strtolower($value), self::$keywords)) { + if (in_array(strtolower($value), $keywords)) { $this->addError($attribute, $this->getAttributeLabel($attribute) . ' cannot take a reserved PHP keyword.'); } } diff --git a/framework/yii/gii/Module.php b/framework/yii/gii/Module.php index 1f3be20..a0f4a05 100644 --- a/framework/yii/gii/Module.php +++ b/framework/yii/gii/Module.php @@ -53,7 +53,6 @@ class Module extends \yii\base\Module { parent::init(); foreach (array_merge($this->coreGenerators(), $this->generators) as $id => $config) { - $config['id'] = $id; $this->generators[$id] = Yii::createObject($config); } } diff --git a/framework/yii/gii/assets/main.css b/framework/yii/gii/assets/main.css index 3748bf0..f1cecc5 100644 --- a/framework/yii/gii/assets/main.css +++ b/framework/yii/gii/assets/main.css @@ -41,3 +41,16 @@ body { .hint-block { display: none; } + +table.code-files .file { + +} + +table.code-files .action { + width: 100px; +} + +table.code-files .check { + width: 25px; + text-align: center; +} diff --git a/framework/yii/gii/controllers/DefaultController.php b/framework/yii/gii/controllers/DefaultController.php index 943c084..f206c61 100644 --- a/framework/yii/gii/controllers/DefaultController.php +++ b/framework/yii/gii/controllers/DefaultController.php @@ -17,6 +17,13 @@ use yii\web\HttpException; class DefaultController extends Controller { public $layout = 'generator'; + /** + * @var \yii\gii\Module + */ + public $module; + /** + * @var \yii\gii\Generator + */ public $generator; public function actionIndex() @@ -28,9 +35,19 @@ class DefaultController extends Controller public function actionView($id) { $generator = $this->loadGenerator($id); - return $this->render('view', array( - 'generator' => $generator - )); + $params = array('generator' => $generator); + if (isset($_POST['preview']) || isset($_POST['generate'])) { + if ($generator->validate()) { + $files = $generator->prepare(); + if (isset($_POST['generate'], $_POST['answers'])) { + $params['result'] = $generator->save($files, $_POST['answers']); + } else { + $params['files'] = $files; + } + } + } + + return $this->render('view', $params); } public function actionCode($file) @@ -43,10 +60,18 @@ class DefaultController extends Controller } + /** + * Loads the generator with the specified ID. + * @param string $id the ID of the generator to be loaded. + * @return \yii\gii\Generator the loaded generator + * @throws \yii\web\HttpException + */ protected function loadGenerator($id) { if (isset($this->module->generators[$id])) { - return $this->generator = $this->module->generators[$id]; + $this->generator = $this->module->generators[$id]; + $this->generator->load($_POST); + return $this->generator; } else { throw new HttpException(404, "Code generator not found: $id"); } diff --git a/framework/yii/gii/generators/controller/Generator.php b/framework/yii/gii/generators/controller/Generator.php index 1deb1c1..04fee04 100644 --- a/framework/yii/gii/generators/controller/Generator.php +++ b/framework/yii/gii/generators/controller/Generator.php @@ -8,6 +8,8 @@ namespace yii\gii\generators\controller; use Yii; +use yii\gii\CodeFile; +use yii\helpers\Html; /** * @@ -31,33 +33,25 @@ class Generator extends \yii\gii\Generator one or several controller actions and their corresponding views.'; } - public function renderForm() - { - return Yii::$app->getView()->renderFile(__DIR__ . '/views/form.php', array( - 'model' => $this, - )); - } - public function rules() { return array_merge(parent::rules(), array( array('controller, actions, baseClass', 'filter', 'filter' => 'trim'), array('controller, baseClass', 'required'), - array('controller', 'match', 'pattern' => '/^[\w+\\/]*$/', 'message' => '{attribute} should only contain word characters and slashes.'), - array('actions', 'match', 'pattern' => '/^\w+[\w\s,]*$/', 'message' => '{attribute} should only contain word characters, spaces and commas.'), - array('baseClass', 'match', 'pattern' => '/^[a-zA-Z_][\w\\\\]*$/', 'message' => '{attribute} should only contain word characters and backslashes.'), + array('controller', 'match', 'pattern' => '/^[\w+\\/]*$/', 'message' => 'Only word characters and slashes are allowed.'), + array('actions', 'match', 'pattern' => '/^\w+[\w\s,]*$/', 'message' => 'Only word characters, spaces and commas are allowed.'), + array('baseClass', 'match', 'pattern' => '/^[a-zA-Z_][\w\\\\]*$/', 'message' => 'Only word characters and backslashes are allowed.'), array('baseClass', 'validateReservedWord', 'skipOnError' => true), - array('baseClass, actions', 'sticky'), )); } public function attributeLabels() { - return array_merge(parent::attributeLabels(), array( + return array( 'baseClass' => 'Base Class', 'controller' => 'Controller ID', 'actions' => 'Action IDs', - )); + ); } public function requiredTemplates() @@ -70,32 +64,34 @@ class Generator extends \yii\gii\Generator public function successMessage() { - $link = CHtml::link('try it now', Yii::app()->createUrl($this->controller), array('target' => '_blank')); + $link = Html::a('try it now', Yii::$app->getUrlManager()->createUrl($this->controller), array('target' => '_blank')); return "The controller has been generated successfully. You may $link."; } public function prepare() { - $this->files = array(); - $templatePath = $this->templatePath; + $files = array(); - $this->files[] = new CCodeFile( - $this->controllerFile, + $templatePath = $this->getTemplatePath(); + + $files[] = new CodeFile( + $this->getControllerFile(), $this->render($templatePath . '/controller.php') ); foreach ($this->getActionIDs() as $action) { - $this->files[] = new CCodeFile( + $files[] = new CodeFile( $this->getViewFile($action), $this->render($templatePath . '/view.php', array('action' => $action)) ); } + + return $files; } public function getActionIDs() { - $actions = preg_split('/[\s,]+/', $this->actions, -1, PREG_SPLIT_NO_EMPTY); - $actions = array_unique($actions); + $actions = array_unique(preg_split('/[\s,]+/', $this->actions, -1, PREG_SPLIT_NO_EMPTY)); sort($actions); return $actions; } @@ -113,16 +109,16 @@ class Generator extends \yii\gii\Generator { if (($pos = strpos($this->controller, '/')) !== false) { $id = substr($this->controller, 0, $pos); - if (($module = Yii::app()->getModule($id)) !== null) { + if (($module = Yii::$app->getModule($id)) !== null) { return $module; } } - return Yii::app(); + return Yii::$app; } public function getControllerID() { - if ($this->getModule() !== Yii::app()) { + if ($this->getModule() !== Yii::$app) { $id = substr($this->controller, strpos($this->controller, '/') + 1); } else { $id = $this->controller; @@ -157,10 +153,4 @@ class Generator extends \yii\gii\Generator } return $module->getControllerPath() . '/' . $id . 'Controller.php'; } - - public function getViewFile($action) - { - $module = $this->getModule(); - return $module->getViewPath() . '/' . $this->getControllerID() . '/' . $action . '.php'; - } } diff --git a/framework/yii/gii/generators/controller/templates/controller.php b/framework/yii/gii/generators/controller/templates/controller.php new file mode 100644 index 0000000..5f4343d --- /dev/null +++ b/framework/yii/gii/generators/controller/templates/controller.php @@ -0,0 +1,8 @@ + -
-
-
- 'login-form')); ?> - field($model, 'controller')->hint(' - Controller ID is case-sensitive and can contain module ID(s). For example: -
    -
  • order generates OrderController.php
  • -
  • order-item generates OrderItemController.php
  • -
  • admin/user generates UserController.php within the admin module.
  • -
- '); ?> - field($model, 'baseClass')->hint(' - This is the class that the new controller class will extend from. - Please make sure the class exists and can be autoloaded. - '); ?> - field($model, 'actions')->hint(' - Provide one or multiple action IDs to generate empty action method(s) in the controller. - Separate multiple action IDs with commas or spaces. - '); ?> -
- 'btn btn-primary')); ?> -
- -
-
-
+field($generator, 'controller')->hint(' + Controller ID is case-sensitive and can contain module ID(s). For example: +
    +
  • order generates OrderController.php
  • +
  • order-item generates OrderItemController.php
  • +
  • admin/user generates UserController.php within the admin module.
  • +
+'); ?> +field($generator, 'baseClass')->hint(' + This is the class that the new controller class will extend from. + Please make sure the class exists and can be autoloaded. +'); ?> +field($generator, 'actions')->hint(' + Provide one or multiple action IDs to generate empty action method(s) in the controller. + Separate multiple action IDs with commas or spaces. +'); ?> diff --git a/framework/yii/gii/generators/crud/Generator.php b/framework/yii/gii/generators/crud/Generator.php index 025ff24..8ebecb8 100644 --- a/framework/yii/gii/generators/crud/Generator.php +++ b/framework/yii/gii/generators/crud/Generator.php @@ -24,4 +24,9 @@ class Generator extends \yii\gii\Generator return 'This generator generates a controller and views that implement CRUD (Create, Read, Update, Delete) operations for the specified data model.'; } + + public function getViewFile() + { + return __DIR__ . '/views/form.php'; + } } diff --git a/framework/yii/gii/generators/form/Generator.php b/framework/yii/gii/generators/form/Generator.php index 750a7b8..f7966a0 100644 --- a/framework/yii/gii/generators/form/Generator.php +++ b/framework/yii/gii/generators/form/Generator.php @@ -23,4 +23,10 @@ class Generator extends \yii\gii\Generator { return 'This generator generates a view script file that displays a form to collect input for the specified model class.'; } + + + public function getViewFile() + { + return __DIR__ . '/views/form.php'; + } } diff --git a/framework/yii/gii/generators/model/Generator.php b/framework/yii/gii/generators/model/Generator.php index 936c75a..032c86d 100644 --- a/framework/yii/gii/generators/model/Generator.php +++ b/framework/yii/gii/generators/model/Generator.php @@ -23,4 +23,9 @@ class Generator extends \yii\gii\Generator { return 'This generator generates a model class for the specified database table.'; } + + public function getViewFile() + { + return __DIR__ . '/views/form.php'; + } } diff --git a/framework/yii/gii/generators/module/Generator.php b/framework/yii/gii/generators/module/Generator.php index 7d49122..cff49e9 100644 --- a/framework/yii/gii/generators/module/Generator.php +++ b/framework/yii/gii/generators/module/Generator.php @@ -23,4 +23,10 @@ class Generator extends \yii\gii\Generator { return 'This generator helps you to generate the skeleton code needed by a Yii module.'; } + + + public function getViewFile() + { + return __DIR__ . '/views/form.php'; + } } diff --git a/framework/yii/gii/views/default/_files.php b/framework/yii/gii/views/default/_files.php new file mode 100644 index 0000000..05c8ee5 --- /dev/null +++ b/framework/yii/gii/views/default/_files.php @@ -0,0 +1,64 @@ + + + + + + + + + + + $file): ?> + + + + + + + +
Code FileAction + operation !== CodeFile::OP_SKIP) { + $count++; + } + } + if ($count > 1) { + echo ''; + } + ?> +
+ getRelativePath()), array('code', 'file' => $i), array('class' => 'view-code', 'rel' => $file->path)); ?> + operation === CodeFile::OP_OVERWRITE): ?> + ( $i), array('class' => 'view-code', 'rel' => $file->path)); ?>) + + + operation === CodeFile::OP_SKIP) { + echo 'unchanged'; + } else { + echo $file->operation; + } + ?> + + operation === CodeFile::OP_SKIP) { + echo ' '; + } else { + $key = md5($file->path); + echo Html::checkBox("answers[$key]"); + } + ?> +
diff --git a/framework/yii/gii/views/default/index.php b/framework/yii/gii/views/default/index.php index 57c8da5..426d2fb 100644 --- a/framework/yii/gii/views/default/index.php +++ b/framework/yii/gii/views/default/index.php @@ -19,16 +19,15 @@ $this->title = 'Welcome to Gii';

Start the fun with the following code generators:

- $generator): ?> + $generator): ?>

getName()); ?>

getDescription(); ?>

-

getUrl(), array('class' => 'btn btn-default')); ?>

+

$id), array('class' => 'btn btn-default')); ?>

-

Get More Generators

diff --git a/framework/yii/gii/views/default/view.php b/framework/yii/gii/views/default/view.php index 3cbb914..d0738aa 100644 --- a/framework/yii/gii/views/default/view.php +++ b/framework/yii/gii/views/default/view.php @@ -1,19 +1,59 @@ title = $generator->getName(); +$templates = array(); +foreach ($generator->templates as $name => $path) { + $templates[$name] = "$name ($path)"; +} ?>
-

getName()); ?>

+

title); ?>

+

getDescription(); ?>

- renderForm(); ?> + +
+
+ renderFile($generator->getViewFile(), array( + 'generator' => $generator, + 'form' => $form, + )); ?> + field($generator, 'template')->label(array('label' => 'Code Template'))->dropDownList($templates)->hint(' + Please select which set of the templates should be used to generated the code. + '); ?> +
+ 'preview', 'class' => 'btn btn-primary')); ?> + + + 'generate', 'class' => 'btn btn-danger')); ?> + +
+
+
+ + ' . $result . '
'; + } elseif (isset($files)) { + echo $this->render('_files', array( + 'generator' => $generator, + 'files' => $files, + )); + } + ?> - renderFileList(); ?> +
diff --git a/framework/yii/requirements/views/web/css.php b/framework/yii/requirements/views/web/css.php index d1de7f9..ac0ba1b 100644 --- a/framework/yii/requirements/views/web/css.php +++ b/framework/yii/requirements/views/web/css.php @@ -1627,7 +1627,7 @@ select:focus:invalid:focus { box-shadow: 0 0 6px #f8b9b7; } -.form-actions { +.form-group { padding: 19px 20px 20px; margin-top: 20px; margin-bottom: 20px; @@ -1636,14 +1636,14 @@ select:focus:invalid:focus { *zoom: 1; } -.form-actions:before, -.form-actions:after { +.form-group:before, +.form-group:after { display: table; line-height: 0; content: ""; } -.form-actions:after { +.form-group:after { clear: both; } @@ -1991,7 +1991,7 @@ legend + .control-group { margin-top: 10px; } -.form-horizontal .form-actions { +.form-horizontal .form-group { padding-left: 180px; }