Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gii生成代码学习 #4

Open
erichua23 opened this issue Mar 12, 2013 · 4 comments
Open

Gii生成代码学习 #4

erichua23 opened this issue Mar 12, 2013 · 4 comments
Milestone

Comments

@erichua23
Copy link
Member

No description provided.

@erichua23
Copy link
Member Author

配置Gii

return array(
    ......
    'modules'=>array(
        'gii'=>array(
            'class'=>'system.gii.GiiModule',
            'password'=>'pick up a password here',
            // 'ipFilters'=>array(...a list of IPs...),
            // 'newFileMode'=>0666,
            // 'newDirMode'=>0777,
        ),
    ),
); 

ipFilters
允许使用Gii的ip, 默认只能localhost访问

newFileMode

the permission to be set for newly generated code files.This value will be used by PHP chmod function. Defaults to 0666, meaning the file is read-writable by all users.

newDirMode

the permission to be set for newly generated directories. This value will be used by PHP chmod function. Defaults to 0777, meaning the directory can be read, written and executed by all users.

@erichua23
Copy link
Member Author

扩展Gii

两种扩展方式

  1. 改现有代码生成器的代码模版
  2. 写新的代码生成器

代码生成器的代码目录结构

structure_of_gii_code_generator

关注其中gii/generator/model的结构, 其中个部分功能为

model/                      代码生成器根目录
   ModelCode.php               the code model used to generate code
   ModelGenerator.php        the code generation controller
   views/                             containing view scripts for the generator
      index.php               the default view script
   templates/                containing code template sets
      default/                  the 'default' code template set
         model.php           the code template for generating model class code

ModelCode

class ModelCode extends CCodeModel
abstract class CCodeModel extends CFormModel

ModelGenerator

class ModelGenerator extends CCodeGenerator
class CCodeGenerator extends CController

自定义代码生成器的目录位置

Gii在 GiiModule::generatorPaths 指定的目录下查找可用的代码生成器.

return array(
    'modules'=>array(
        'gii'=>array(
            'class'=>'system.gii.GiiModule',
            'generatorPaths'=>array(
                'application.gii',   // 代码生成器所在的目录, 可以使用yii的别名
            ),
        ),
    ),
);

Gii looks for available generators in a set of directories specified by the GiiModule::generatorPaths property.

上面的配置会让Gii在别名为application.gii的目录中去寻找代码生成器, Gii会默认去此目录下的generators中寻找代码生成器. system.gii.generators. 默认位置为system.gii.generators.

是可以有两个同名的代码生成器在分别在不同目录中的, 这样使用那个一代码生成器就取决于在GiiModule::generatorPaths目录定义的数据.

@erichua23
Copy link
Member Author

自定义代码模版

添加相应目录

添加protected/gii/model/templates/erichua/目录, 其中model表示要自定义model的代码生成, templates说明是要通过改模版的方式修改, 添加了名为erichua的模版.

再复制framework/gii/generators/model/templates/default/model.php到erichua目录下面
文档上面说是需要添加application.gii到GiiModule::generatorPaths中, 不过目前已经不需要此步骤, 在没有添加的时候, Gii能正常找到模版, 应该是现在版本的Gii现在默认到application.gii下查找代码生成器模版.

开始真正的自定义模版

打开protected/gii/model/templates/erichua/model.php编辑它, 此时可以把model.php看作是Yii中的view文件., 其中我们可以使用一些预定的变量, 这些变量由对应的code generator提供. 下面是Gii自带的model.php中关于变量的一些注释:

/**
 * This is the template for generating the model class of a specified table.
 * - $this: the ModelCode object
 * - $tableName: the table name for this class (prefix is already removed if necessary)
 * - $modelClass: the model class name
 * - $columns: list of table columns (name=>CDbColumnSchema)
 * - $labels: list of attribute labels (name=>label)
 * - $rules: list of validation rules
 * - $relations: list of relations (name=>relation declaration)
 */

下面我们将会查看一下code generator

@erichua23
Copy link
Member Author

创建新的代码生成器

同样, 先创建protected/gii/widget目录, 在此目录下, 创建如下文件

  • WidgetGenerator.php: contains the WidgetGenerator controller class. This is the entry point of the widget generator.

class WidgetGenerator extends CCodeGenerator
{
    public $codeModel='application.gii.widget.WidgetCode';
}

指明使用application.gii.widget.WidgetCode来作为代码生成器我Model. 在CCodeGenerator $codeModel的声明.

class CCodeGenerator extends CController
{
     // ...
     /**
     * @var string the code model class. This can be either a class name (if it can be autoloaded)
     * or a path alias referring to the class file.
     * Child classes must configure this property with a concrete value.
     */
    public $codeModel;
    // ...

这里设置的$codeModel会在CodeGenerator中的prepare方法中使用:

$model->saveStickyAttributes();
$model->prepare();

为了弄清WidgetGenerator , 先来看一下CCodeGenerator, CCodeGenerator中的actionIndex是代码生成时展示页面和生成代码使用的.

/**
 * The code generation action.
 * This is the action that displays the code generation interface.
 * Child classes mainly need to provide the 'index' view for collecting user parameters
 * for code generation.
 */
public function actionIndex()
{
    $model=$this->prepare();
    if($model->files!=array() && isset($_POST['generate'], $_POST['answers']))
    {
        $model->answers=$_POST['answers'];
        $model->status=$model->save() ? CCodeModel::STATUS_SUCCESS : CCodeModel::STATUS_ERROR;
    }
    $this->render('index',array(
        'model'=>$model,
    ));
}

下面这段代码是在预览代码是使用的

public function actionCode()
{
    $model=$this->prepare();
    if(isset($_GET['id']) && isset($model->files[$_GET['id']]))
    {
        $this->renderPartial('/common/code', array(
            'file'=>$model->files[$_GET['id']],
        ));
    }
    else
        throw new CHttpException(404,'Unable to find the code you requested.');
}

这些里面都调用了prepare方法. 此方法关键在于初始化对应的CodeModel, 同时也调用了CodeModel自己的prepare方法, 子类CCodeModel的prepare方法需要自己去实现 下面是次示例中WidgetCode的prepare

    public function prepare()
    {
        $path=Yii::getPathOfAlias('application.components.' . $this->className) . '.php';
        $code=$this->render($this->templatepath.'/widget.php');

        $this->files[]=new CCodeFile($path, $code);
    }

prepare中调用了自己的render方法, 此方法在CCodeModel中定义, 此方法返回制定路径的模版.
最后将获得的代码模版放到CCodeFile来封装, CCodeFile最后会完成代码文件生成的工作. CCodeModel子类的prepare方法调用完毕以后回到CCodeGenerator的prepare, 此时返回$model已经带有files(为CCodeFile类型), CCodeGenerator的prepare在昨晚CCodeModel的初始化工作以后也基本完成任务, 返回刚刚生成并初始化过的$model. 程序回到action执行, 此处继续用actionIndex为例, 在调用玩prepare以后, 会检查返回的$model是否带有files(CCodeFile类型), 如果带有, 这回调用$model的save方法, 此方法在CCodeModel中定义, 在此方法总会遍历, $model->files, 分别调用他们的save方法, 支持代码文件生成完毕.

其调用的关系图
sequence

  • WidgetCode.php: contains the WidgetCode model class. This class has the main logic for code generation.

class WidgetCode extends CCodeModel
{
    public $className;

    public function rules()
    {
        return array_merge(parent::rules(), array(
            array('className', 'required'),
            array('className', 'match', 'pattern'=>'/^\w+$/'),
        ));
    }

    public function attributeLabels()
    {
        return array_merge(parent::attributeLabels(), array(
            'className'=>'Widget Class Name',
        ));
    }

    public function prepare()
    {
        $path=Yii::getPathOfAlias('application.components.' . $this->className) . '.php';
        $code=$this->render($this->templatepath.'/widget.php');

        $this->files[]=new CCodeFile($path, $code);
    }
}
  • views/index.php: 代码生成页面

<h1>Widget Generator</h1>
<?php $form=$this->beginWidget('CCodeForm', array('model'=>$model)); ?>
    <div class="row">
        <?php echo $form->labelEx($model,'className'); ?>
        <?php echo $form->textField($model,'className',array('size'=>65)); ?>
        <div class="tooltip">
            Widget class name must only contain word characters.
        </div>
        <?php echo $form->error($model,'className'); ?>
    </div>
<?php $this->endWidget(); ?>
  • templates/default/widget.php: widget代码模版

<?php echo '<?php'; ?>
class <?php echo $this->className; ?> extends CWidget
{
    public function run()
    {

    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant