How to develope your app with this project.
这个代码生成器其实并不难,我只是把一个简单的应有的东西理清罢了。如果你看了这个功能觉得很不错,想加入到你的系统里面,或者你的开发框架是其它的比如Yii、Ci、Yaf、Zend,或者跟PHP都不搭边,也没事,让我来告诉你怎么使用或者如何做你自己的代码生成器。
代码生成器生成的内容:
PHP的一些主流框架都可以做到通用的单表增删改查,这里不再赘述。 前台视图我提一下,最多就四个界面:列表、添加、修改和查看。 列表是表格,功能就一个显示和查询,难的地方在于自定义显示和查询的字段,这个后面具体会提到。 添加和修改界面生成时只要将数据库表字段类型与表单类型对应即可,比如varchar生成文本框,enum生成列表框。
这里以用户角色表为例,用户ID和角色ID分别是关联用户表和角色表
CREATE TABLE `user_role` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uid` int(11) unsigned NOT NULL COMMENT '用户ID',
`rid` int(11) unsigned NOT NULL COMMENT '角色ID',
PRIMARY KEY (`id`),
UNIQUE KEY `index_uid_rid` (`uid`,`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='用户角色'$$
生成时,我做了如下的处理:
想要动态,也就是随时可以修改和重新设置,那么就得把查询和显示的字段信息作为参数存下来,不能硬编码写到代码里面。条件 动态显示是这样,动态查询的话稍微复杂一点,因为查询条件的处理要复杂一点:查询的匹配方式主要有三种,等于、模糊和区间查询,区间查询的话需要生成2个控件,这个让用户在选择查询字段的时候选择。如果是外键字段,那么生成一个查找带回框或者列表框都可以。
通过代码生成,我们希望的是不用写一行代码就能让设计器本身提供基本的操作数据功能和界面,为了达到这个目的,你需要在设计数据库时提供尽可能详尽的信息:字段说明以及表关系。
在列表界面中,字段说明用于填充表格的列标头th中的内容(用户名、姓名、邮箱);添加界面中的字段说明也是一样。
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`email` varchar(100) DEFAULT NULL COMMENT 'email',
`display_name` varchar(50) DEFAULT NULL COMMENT '姓名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8$$
| 用户名 | 姓名 | 状态 | 操作 | ||
|---|---|---|---|---|---|
| admin | 管理员 | admin@admin.com | |||
| user | 用户 | user@user.com | |||
| ... | ... | ... | |||
| ... | ... | ... |
Heads up! 在建立表结构时,请为字段提供 COMMENT 字段说明,用于生成代码时填充列表界面的标头和添加界面中的字段说明。
<div class="control-group">
<label class="control-label" for="字段ID">字段说明</label>
<div class="controls">
<input type="text" value="字段默认值" name="字段ID" id="字段ID" class="{验证类型}" placeholder="">
<label class="help-inline">提示文字</label>
</div>
</div>
生成时能够根据字段类型自动生成对应的表单元素,对应关系如下
| 数据表字段 | 表单元素 | 前台验证 |
|---|---|---|
| 主键PRI | hidden | |
| char,varchar | text | |
| text,blob | area | |
| enum | select | |
| bit | checkbox | |
| int,decimal,float,double | text | {number:true,range:[下限,上限]'} |
| data,datetime | date | dateISO:true |
| NOT NULL | {required:true} | |
| 其它 | 等待您的扩展 |
模块列表显示了当前数据库中的所有表,选择修改进入表单设计器,可以修改数据表对应的模块名、所属分组以及显示字段等。
用于后台生成tpl模板和Model,主要设计以下功能:
插入列和更新列对应Model中的 $insertFields 和 $updateFields
验证规则 和 自动生成 对应Model中的 $_validate 、 $_auto
具体文档详见ThinkPHP官方文档 插入及更新过滤 自动验证 自动完成
在列表列中有一列“查询”,用来设置某个字段是否是查询字段。设置可查询后,在前台的列表中,会生成查询条件。样式如下
控件类型:同添加界面的控件类型
数据来源(主要是select和引用的数据来源)
匹配方式 参照表达式查询 ,实际使用时,只用前3种:eq(默认),between和like
| 表达式 | 含义 |
|---|---|
| EQ | 等于(=) |
| BETWEEN | 区间查询 |
| LIKE | 模糊查询 |
| NEQ | 不等于(<>) |
| GT | 大于(>) |
| EGT | 大于等于(>=) |
| LT | 小于(<) |
| ELT | 小于等于(<=) |
| [NOT] IN | (不在)IN 查询 |
| EXP | 表达式查询,支持SQL语法 |
在建立表结构时,如果同时建立了表间的关联,则系统在生成模板时能够自动生成表关系。否则,需要在这里进行表间关系设计。
比如,在文章表article与用户表user关联,每个文章都属于一个用户,一个用户有多篇文章,
用sql关系表达就是 article.user_id=user.id
ThinkPHP官方文档 关联模型
以下这个表间关系设计界面是把关联模型和表间关系设计界面合并了,如果无需用到关联模型,仅仅只用引用某个表用于添加和列表中显示,那么按照下面这样操作即可
关联条件留空即表示 关联主键=关联外键,比如这里 article.user_id=user.id
显示字段表示,通过查找带回时显示的字段
在article的添加界面中,user_id就应该作为引用字段,单击后面的查找按钮时,弹出User模块的引用,文本框内的内容为“显示字段”,在这里是username
<div class="control-group">
<label class="control-label" for="user_id">作者</label>
<div class="controls">
<div class="input-append" id="broadband_refer_user_1">
<input type="hidden" value="" name="id" id="id" data-target="user_id" class="{digits:true,range:[-2147483648,2147483647]}" placeholder="">
<input type="text" value="" name="username" id="user_name" data-target="user_name" class="{digits:true,required}" placeholder="" readonly="">
<a data-target="#modal-refer" href="/User/refer/article_refer_user_1.htm" data-toggle="modal"><span class="add-on"><i class="icon-search"></i></span></a>
</div>
<label class="help-inline"></label>
</div>
</div>
系统会生成4个文件到对应的文件夹下,暂不支持独立分组
生成的Action类继承CommAction,提供了以下方法,配合生成的模板,能够完整的完成所提供的功能:
默认 index
引用 refer
日志 log
添加 add
查看 view
编辑 edit
保存 save
删除 delete
导入 import
导出 export
上传 upload
扩展 operate
系统生成类位于Lib/Comm/CodeAction.class.php,你可以通过扩展加入你想要的通用功能。
如果你不想要某些只具有CommAction功能的Action类实体文件,可以通过在在配置文件中设置 空模块 空操作 来将这些模块定向到EmptyAction(位于CodeAction同目录下)
class UserModel extends AdvModel {
protected $fields = array (
//0 => 'id',
//1 => 'name',
//'_autoinc' => true,
//'_pk' => 'id',
//'_type' => array (
// 'id' => 'int(11) unsigned',
// 'name' => 'varchar(50)',
//),
$data.fields}
);
protected $insertFields = array();
protected $updateFields = array();
protected $readonlyField = array();
public $viewFields = array(
//'Category'=>array('title'=>'category_name', '_on'=>'Blog.category_id=Category.id','_type'=>'INNER'),
);
protected $_filter = array(
//'过滤的字段'=>array('写入过滤规则','读取过滤规则',是否传入整个数据对象),
)
protected $_validate = array(
//array(验证字段,验证规则,错误提示,[验证条件,附加规则,验证时间])
)
protected $_auto = array (
//array(填充字段,填充内容,[填充条件,附加规则])
}
protected $_map = array(
//'txt_user' =>'username', //把表单中的text_user字段映射到数据表的username字段
)
protected $_scope = array(
'default'=>array(
//'table'->array(''=>''),
//'field'->array(''=>''),
//'where'=>array(''=>''),
//'order'=>array(''=>''),
//'limit'->array(''=>''),
),
)
}Class UserModel extends CommAction{
}<div class="row-fluid">
<form class="form-inline form-horizontal" action="{:U('save')}" method="post" id='form'>
<div class="control-group">
<label class="control-label" for="id"></label>
<div class="controls">
<input type="hidden" value="" name="id" id="id" class="{required:true,digits:true,range:[0,4294967295]}" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="username">用户名</label>
<div class="controls">
<input type="text" class="{required:true,maxlength:50,}" value="" name="username" id="username" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="email">email</label>
<div class="controls">
<input type="text" class="{maxlength:100,}" value="" name="email" id="email" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="password">密码</label>
<div class="controls">
<input type="text" class="{maxlength:45,}" value="" name="password" id="password" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="display_name">姓名</label>
<div class="controls">
<input type="text" class="{maxlength:50,}" value="" name="display_name" id="display_name" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="sex">性别</label>
<div class="controls">
<select id="sex" name="sex" class="selected" data-value="未知">
<option value ="男">男</option> <option value ="女">女</option> <option value ="未知">未知</option> </select> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="phone">手机</label>
<div class="controls">
<input type="text" class="{maxlength:50,}" value="" name="phone" id="phone" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="card_id">身份证号</label>
<div class="controls">
<input type="text" class="{maxlength:18,}" value="" name="card_id" id="card_id" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="photo">头像</label>
<div class="controls">
<input type="text" class="{maxlength:255,}" value="" name="photo" id="photo" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="qq">qq</label>
<div class="controls">
<input type="text" class="{maxlength:20,}" value="" name="qq" id="qq" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="weibo">微博</label>
<div class="controls">
<input type="text" class="{maxlength:100,}" value="" name="weibo" id="weibo" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="register_time">注册时间</label>
<div class="controls">
<input type="text" class="{dateISO:true,date:true,}" name="register_time" id="register_time" rel="datepicker" data-date="" data-date-format="yyyy-mm-dd"> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="last_login_time">上次登录</label>
<div class="controls">
<input type="text" class="{dateISO:true,date:true,}" name="last_login_time" id="last_login_time" rel="datepicker" data-date="" data-date-format="yyyy-mm-dd"> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="status">状态</label>
<div class="controls">
<input type="text" class="{maxlength:255,}" value="" name="status" id="status" placeholder=""> <label class="help-inline"></label>
</div>
</div>
</form>
</div><div class="row-fluid">
<form class="form-inline form-horizontal" action="{:U('save')}" method="post" id='form'>
<div class="control-group">
<label class="control-label" for="id"></label>
<div class="controls">
<input type="hidden" value="{$data.id}" name="id" id="id" class="{required:true,digits:true,range:[0,4294967295]}" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="username">用户名</label>
<div class="controls">
<input type="text" class="{required:true,maxlength:50,}" value="{$data.username}" name="username" id="username" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="email">email</label>
<div class="controls">
<input type="text" class="{maxlength:100,}" value="{$data.email}" name="email" id="email" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="password">密码</label>
<div class="controls">
<input type="text" class="{maxlength:45,}" value="{$data.password}" name="password" id="password" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="display_name">姓名</label>
<div class="controls">
<input type="text" class="{maxlength:50,}" value="{$data.display_name}" name="display_name" id="display_name" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="sex">性别</label>
<div class="controls">
<select id="sex" name="sex" class="selected" data-value="{$data.sex}">
<option value ="男">男</option> <option value ="女">女</option> <option value ="未知">未知</option> </select> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="phone">手机</label>
<div class="controls">
<input type="text" class="{maxlength:50,}" value="{$data.phone}" name="phone" id="phone" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="card_id">身份证号</label>
<div class="controls">
<input type="text" class="{maxlength:18,}" value="{$data.card_id}" name="card_id" id="card_id" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="photo">头像</label>
<div class="controls">
<input type="text" class="{maxlength:255,}" value="{$data.photo}" name="photo" id="photo" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="qq">qq</label>
<div class="controls">
<input type="text" class="{maxlength:20,}" value="{$data.qq}" name="qq" id="qq" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="weibo">微博</label>
<div class="controls">
<input type="text" class="{maxlength:100,}" value="{$data.weibo}" name="weibo" id="weibo" placeholder=""> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="register_time">注册时间</label>
<div class="controls">
<input type="text" value="{$data.register_time}" class="{dateISO:true,date:true,}" name="register_time" id="register_time" rel="datepicker" data-date="" data-date-format="yyyy-mm-dd"> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="last_login_time">上次登录</label>
<div class="controls">
<input type="text" value="{$data.last_login_time}" class="{dateISO:true,date:true,}" name="last_login_time" id="last_login_time" rel="datepicker" data-date="" data-date-format="yyyy-mm-dd"> <label class="help-inline"></label>
</div>
</div><div class="control-group">
<label class="control-label" for="status">状态</label>
<div class="controls">
<input type="text" class="{maxlength:255,}" value="{$data.status}" name="status" id="status" placeholder=""> <label class="help-inline"></label>
</div>
</div>
</form>
</div>系统生成代码后,你需要根据自己的业务对代码进行二次开发和扩展,完成自定义开发后,你可能需要将整个系统的模块和操作生成RBAC的节点数据,以便进行权限或菜单管理。
在模块管理界面中,选择模块后单击生成节点即可。
通过读取APP_GROUP_LIST,获取所有分组,然后遍历各个分组下以*Action.class.php的文件,建立该Action对象,获取该对象的所有方法,过滤掉ThinkPHP本身提供的底层方法,获取到的便是用户的操作方法列表,插入到数据库中即可。
public function getFunction($module){
if(empty($module))return null;
$action=A($module);
$functions=get_class_methods($action);
//ThinkPHP的Action底层方法
$inherents_functions = array(
'_initialize','__construct','getActionName','isAjax','display','show','fetch',
'buildHtml','assign','__set','get','__get','__isset',
'__call','error','success','ajaxReturn','redirect','__destruct'
);
foreach ($functions as $func){
if(!in_array($func, $inherents_functions)){
$customer_functions[]=$func;
}
}
return $customer_functions;
}