rrbrr/cgf

generate form from table

v1.1.2 2024-01-09 17:45 UTC

This package is auto-updated.

Last update: 2024-05-09 18:44:02 UTC


README

随着现在框架发展的发展,本来已经放弃了这个项目。但现在依然看到大量的底层码农在写增删改查,实在受不了。于是连夜捡起这个项目。 能直接无代码实现增删改,直接解放后端苦逼码农。

CGF(Comment Generate Form)

根据表字段注释自动实现CURD。只要建好表就拥有了添加,修改,列表,搜索基本功能的接口。

安装 install

composer require rrbrr/cgf

thinkphp中使用方法(支持thinkphp8)

####1. 直接去vendor/rrbrr/cgf/Error.php复制到app/controller中 ####2. 手工在app/controller目录下创建Error.php文件,写入以下代码

<?php
namespace app\controller;
use Cgf\Framework\Thinkphp\BaseController;

class Error extends BaseController
{
    public function __call($method, $args)
    {
        return 'error request!';
    }
}

3. 然后就直接访问 /表名/index,如 /article/index,/article/save

###默认支持以下方法,如果想修改可以打开Cgf\Framework\Thinkphp\BaseController自己修改

  1. index 列表
  2. save 添加/保存
  3. delete 删除

比如建个文章表

CREATE TABLE `article` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT NULL,
  `content` text,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;

然后就可以用curd api接口了。

  1. 添加新文章 http://www.test.com/article/save?title=标题&content=内容
{
	"code": 1,
	"msg": "成功",
	"data": {
		"id": "1"
	}
}
  1. 文章列表 http://www.test.com/article/index
{
	"code": 1,
	"msg": "成功",
	"data": {
		"total": 1,
		"per_page": 20,
		"current_page": 1,
		"last_page": 1,
		"data": [{
			"id": 1,
			"title": "标题",
			"content": "内容",
			"create_time": "2020-07-17 18:58:44"
		}]
	}
}

搜索可以直接指定字段及关键字即可,如:http://www.tesuo.com/article/index?title=标题

  1. 文章详情 http://www.test.com/article/show?id=1
{
	"code": 1,
	"msg": "成功",
	"data": {
		"vo": {
			"id": 1,
			"title": "标题",
			"content": "内容",
			"create_time": "2020-07-17 18:58:44"
		}
	}
} 
  1. 修改文章 http://www.test.com/article/save?id=1&title=新标题
{
	"code": 1,
	"msg": "成功",
	"data": {
		"id": ""
	}
}

设计思想

根据每个功能的配置文件来生成对应的表单界面,验证规则,sql查询字段。

流程 1.定义配置

return array(
    'base' =>
        array(
            'username'    =>
                array(
                    'name' => 'uesrname',
                    'type' => 'text',
                    'size' => 10,
                    'zh'   => 'id',
                ),
            'status_flag' =>
                array(
                    'name'      => 'status_flag', //数据表字段名
                    'type'      => 'text',        //类型
                    'size'      => 10,
                    'rawOption' => '0:禁用,1:正常', //可选值
                    'options'   =>
                        array(
                            0 => '禁用',
                            1 => '正常',
                        ),
                    'zh'        => '用户状态',            //后台列表中展示的标题
                    'show_text' => 'status_flag_text',  //将枚举的数学类型的值转为文本显示
                ),
        )
);

2.解析配置,生成相应的模板文件和后端处理程序。

一般情况不会手工写这个配置,都是根据表的定义来自动生成。 表格式如下说明(详细文档见doc目录中):

表定义的参考格式

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '标题-hidden|0111',
  `username` varchar(255) NOT NULL DEFAULT '' COMMENT '用户名--用户名为字符|1111-0011-11|require:用户名必须填写-unique-<</\\w{3,6}/i>>:用户名不合法',
  `password` varchar(255) DEFAULT '' COMMENT '密码-password|1100-1110-0|require:密码必须填写',
  `email` varchar(255) DEFAULT NULL COMMENT '邮箱|15-12-3|require:邮箱必须填写-email:邮箱格式不正确',
  `birthday` date DEFAULT NULL COMMENT '生日|1111|require:密码必须填写',
  `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态-select-禁用则不显示|1111|require|0:禁用,1:正常,2:审核中',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间|0010',
  `flag` varchar(255) NOT NULL DEFAULT '' COMMENT '标记-select|1100|require|function=flag_options()|tpl_function=img()',
  `intro` text COMMENT '用户介绍-editor|1100-1100-11',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表|lock-birthday|编辑:id,查看用户浏览记录:id| add-export-showMenu';

参考格式说明

用户名--用户名为字符|1111|require:用户名必须填写-unique-<</\w{3,6}/i>>:用户名不合法

[ 用户名 ] 控件label

[ - ] 光有1个[ - ],没有内容,表示省略了内容,也就是省略了个控件类型,使用默认的控件类型

[ 用户名为字符 ],表示tip提示信息

[ 1111 ] 表示用户名在增加,修改,列表,搜索页面都显示

[ require ] 表示必填, unique表示为惟一,

[ <</\w{3,6}/i>>:用户名不合法 ] 正则验证用户名,此正则意思是,用户名为3到6位的字符,并且不符合此正则的则报错 “用户名不合法”

状态-select-禁用则不能访问 | 15| reqiure:必须填写 | 0:禁用,1:正常,2:审核中

[ 状态 ] 控件label名为

[ select ] 表示使用select控件

[ 禁用则不能访问 ] 表示提示内容为

[ 15 ] 为1111的10进制,等同于1111

[ reqiure:必须填写 ] 表示必填,错误提示为:必须填写

[ 0:禁用,1:正常,2:审核中 ] 表示状态这个select控件有3个选项,0,1,2表示key

字段注释格式说明

以 |-,之类的做分隔
注释标题 - htm控件类型 - 提示 |后台显示页面-用户中心-前台显示页面 | 验证类型1-验证类型2 | 选项|显示模板

第一部分 描述字段lable、控件类型、提示信息

注释标题: 一般是字段的中文标题,form表单的label
html控件类型: select,checkbox,input,textare,datepicker,editor等,更多的控件需要你自己来实现。
提示:一般是此字段的填写规范,如:允许字母或数字

第二部分 描述在哪些页面显示

  1. 位表示法(1表示显示,0不显示)
添加页 修改页 列表页 搜索页
1 1 0 0

以上表示在添加和修改页显示此字段

  1. 10进制表示法,就是上面的位表示法将二进制数转成10进制数 添加页|修改页|列表页|搜索页 ---|---|---|--- 1 | 1 | 0 | 0

1100 转成 10进制 = 12 也就是说,12也表示添加页,修改页显示字段。

更多例子:
添加,修改,列表,搜索全显示 1111 = 15
添加,修改,列表都要显示则是 1110 = 14
添加,修改显示,列表不显示 1100 = 10
添加,修改不显示,列表显示,一般像创建时间就是这样 0010 = 1

如果一个项目有多个模块,每个模块显示不同的字段。则可以根据模块来配置。多个模块之间用 - 分隔。目前内置3个模块 后台 - 用户中心 - 前台 如 1111-0011-11 表示后台所有页面显示,用户中心在列表和搜索页显示,前台在列表和详情页显示。 由于前台一般只有列表和搜索页,所以只有2位。

第三部分 描述前后台校验方式

校验类型:reqiure,email,username,mobile等,用于后台校验,对应thinkphp的校验格式 , 也支持前台验证,目前使用validform验证格式,也可使用正则表达式。

第四部分 描述选项的key和value

选项: 选项1:选项1值,选项2:缺项2值

第五部分 回调函数处理

比如保存多选的tag时,页面上传过来的是个数组 tag = [a,b,c] ,但想保存为 a,b,c,则此字段可使用函数回调来处理
写法 implode=,,### 等号前面是函数名,后面是参数,用逗号分隔。像implode函数,第一参数就是逗号,则需要转义写为 \,

表本身注释格式说明

表的中文名|属性|操作|排序|页面按钮

  1. 表的中文名:表示表的作用。

  2. 属性: 可选值有 lock,lock表示生成相关cgf文件后,会锁定配置文件,再次修改不会生成新配置文件。

  3. 每行记录的操作:
    记录可以进行的操作项
    常用有:编辑,删除。
    写法:edit:编辑:id, edit表示js的方法名,编辑表示页面上显示的中文名,id表示参数

  4. 排序
    默认排序字段-倒序

  5. 页面按钮 页面上显示的按钮,用 - 分隔
    可选值:add,export,showMenu add 显示添加按钮 export 显示导出按钮
    showMenu 在左侧菜单显示

例:用户表|lock|edit:编辑:id,del:删除:id|create_time-desc|export-showMenu|function_name

函数使用

1.show_func 显示列表数据时,调用函数,参数为当前字段的值。 2.tpl_function=img() 会被解析成配置 ['flag'=>['tpl_function'=>'img()'] 3.选项字段也可定义函数,function=flag_options()将会调用flag_options返回所有选项

例1:显示支付方式。


 //cgf 格式
 `channel` varchar(255) DEFAULT '' COMMENT '支付渠道|0011-0-11|require|show_func=get_pay', 
 
 // channel值一般是 alipay,wxpay等。但希望显示出来的是支付宝,微信。就可以用函数来处理了。

 //php 代码
 function get_pay($selfValue){
    $paymethod = ['alipay'=>'支付宝','wxpay'=>'微信'];
    return $paymethod[selfValue];
 }
 
 //这样在列表里就能看到支付方式的汉字了,而不是字母代号


例2:多参数支持,显示产品详情链接.订单里显示产品名,想要点击能打开产品详情,详情页需要传产品id参数,可用下面方式。

方式一:

//cgf格式
`course_title` varchar(255) NOT NULL DEFAULT '' COMMENT '产品名称|1011||show_func=order_course_title',

//php
function order_course_title($title,$key,$v){ // 调用代码:call_user_func_array(函数名,[字段值,字段名,此行记录所有数据]);
    
    $title = $v['course_title'];
    $url = "http://www.21mmm.com/course/{$v['course_id']}";
    $url = "<a href='{$url}' target='_blank' title='{$title}'>$title</a>";
    return $url;
}

方式二:在函数名后,指定参数course_id。 未来也可以实现可编程方式。 如: |fcuntion order_course_title(course_id), 直接写代码,然后通过程序来解释cgf代码

//cgf格式
`course_title` varchar(255) NOT NULL DEFAULT '' COMMENT '产品名称|1011||show_func=order_course_title-course_id',

//php
function order_course_title($title,$key,$course_id){
    
    $title = $v['course_title'];
    $url = "http://www.21mmm.com/course/{$v['course_id']}";
    $url = "<a href='{$url}' target='_blank' title='{$title}'>$title</a>";
    return $url;
}

未来支持默认函数调用,如order表user_id字段 "用户id|1111||show_func" 不用加=指定函数,只要定义了show_func,就会默认调用 order_user_id()这个函数

例2:显示分类名。 分类一般用分类id关联,但显示时,却希望显出中文。

// cgf格式
  `category_id` int(11) unsigned NOT NULL COMMENT '分类id-select|1111|require|function=get_select_by_category',
//php 代码
  function get_select_by_category(){
    $r = M('Category')->field('id,title')->select();
    return $r;  //从分类表,取出分类id,分类title

  }

  //这样category_id 显示的select就会是这样的 <option value="分类id1">分类tilte1</option>

配置

$cgfConf                       = []; //
$cgfConf['dbConfig']           = ['host'=>'localhost','dbname'=>'test','username'=>'root','password'=>'123456','type'=>'mysql']; //数据库连接配置
$cgfConf['savePath']           = $appBasePath . "/Cgf/definition"; //保存cgf生成的定义文件
$cgfConf['framework']          = 'thinkphp'; //使用的框架
$cgfConf['validate']           = 'thinkphp'; //使用验证
$cgfConf['form']               = 'bootstrap'; //表单使用的框架
$cgfConf['currentName']        = 'common'; //当前模块名
$cgfConf['tableName']          = $tableName; //表名
$cgfConf['controllerName']     = $this->controllerName; //控制器名
$cgfConf['appRootPath']        = $appBasePath; //框架应用程序根目录
$cgfConf['parentTemplatePath'] = $appBasePath . '/view/public/'; //cgf生成模板使用的父模板,cgf会根据这里的模板来生成应用模板
$cgfConf['templateSavePath']   = $appBasePath . "/view/{$tableName}"; //cgf生成的模板保存路径
$cgfConf['availableModule']    = ['common', 'admin']; //可用模块
$cgfConf['autoHiddenPrimaryKey']    = true; //是否将主键表单类型设为hidden

跨库支持

 $dbConnection= [
                   'DB_TYPE'=>'mysql',
                   'DB_HOST'=>'localhost',
                   'DB_PORT' => '3306',
                   'DB_NAME'=>'test',
                   'DB_USER'=>'root',
                   'DB_PWD'=>'123456',
                   'DB_PREFIX'=>'',
                 ]
 //在实例化的时候传入db连接即可
 $tableInfo = new TableInfo('edit',$dbConnection);

#目录结构和设计说明 definition 是所有表定义 Form下是具体表单的实现类,继承Form.class.php Validate下是各框架下的验证实现,继承Validate.php

#definition结构说明

[模块名][页名]

模块名有下列项目

admin 后台 user 用户中心 home 前台

页面有下列项目

all 所有字段定义,等于list定义 add 添加页 edit
list
search

数组定义使用方法

公共属性

name 表单名,一般和字段名相同
type 表单类型,所有表单类型的实现都在Form目录下,要继承Form类
  1. 所有html表单类型都可以。如text,select
  2. 自定义类型
    editor 富文件编辑器
    img 图片上传,带图片预览
    file 文件上传
    files 多文件上传
    datepicker(日期选择控件)
    datetimePicker(时间选择控件)
    datePickerRang(日期范围选择控件)
    datetimePickerRang(时间范围选择控件)
size 表单的尺寸,一般用于text文本框
zh 中文标签名
options 当表单类型是select时的选项,checkbox,radio也可以有此字段。
  1.枚举格式。 如 
   
      'options'=>[
          0=>'禁用'
          1=>'正常',
          2=>'审核中'
        ]
  2.函数获取。 如
      'options'=>[
          'function'=>"get_allf_lag('a','###','@@@')"
        ]
rawOption 数据表字段的原生定义,一般只有表字段定义了选项,才会有。
如 'rawOption' => '0:否,1:是' 
validate 验证规则

验证规则可以有多个,会依次执行验证。

    'validate' => [
        ['require:必须填写',]
        ['<</\w{3,6}/i>> : 用户名不合法'],
        ['checkUsername:用户名已经被使用了'],
    ]
autoComplete

实例

zh 对应字段含义 base=>[ 'flag'=>[ 'name'=>'标致', 'type'=>'select', 'options'=>[ 'function'=>"get_allf_lag('a','###','@@@')" ] ]

'create_time'=>[ 'name'=>'创建时间', 'type'=>'datetime', ],

]

//添加页用时间选择组件 add=>[ 'create_time'=>[ 'name'=>'创建时间', 'type'=>'datetimePicker', ] ]

//搜索页用时间范围组件 search=>[ 'create_time'=>[ 'name'=>'创建时间', 'type'=>'datetimePickerRang', ] ]

//标题文本框 base=>[ 'title'=>[ 'name'=>'标题', 'type'=>'input', //常规是文本框 ] ]

search=>[ 'title'=>[ 'name'=>'标题', 'type'=>'linkbutton', //列表页是链接,点击进入编辑页或跳转到其它页面。只有后台这样。 ] ]

对于create_time添加页和搜索页使用不同组件问题,sql不太好定义。最好用config.非要用sql,也用创建时间-datepicker|datetimePicker 但这种方式也不能解决各模块组件不同的问题。如用户中心搜索页,添加页和后台搜索页,添加页都用不同组件的问题。

base

base 通常是表的所有字段字义,其它表的定义如果要显示关联表的某些字段值,那些显示的字段的信息就是从base里取出来的。 例如: 搜索框增加选项步骤 1.可在base里添加相应的字段。 2.在search里增加。

组件

1.搜索页,根据配置生成输入框,日期选择控件等。但select的选项值却是在生成组件后,再调用函数生成的。 可以将select选项直接与输入框这些控件生成是一起生成。若是回调函数则也是生成组件时调用回调函数。这样避免生成select时来回交互。简化流程。这样就需要在form里实现自己完整的组件,不能依赖于tp的组件了。

列表

1.关联表 related_table 关联表定义,相当于join related_field 关联表中对应的字段,相当于join时右表的关联字段 table_name 关联表 fields => ["state","name"], 关联表要显示的字段 "way" => "add", 展现方式, add表示左表的字段也显示,右表字段也显示。 replace表示左表字段不显示,用右表的字段代替 例: "related_table" => [ "related_field" => "issue_id", "table_name" => "goods_activity", "fields" => ["state"], "way" => "add",//replace 1.add表示显示user_id,并且增加field定义的字段 2.replace 表示用field字段替换掉user_id 'function'=>"date" ]

2.show_text 数字枚举字段,显示对应的文字含义

  1. "class"=>"c_trans_state",//给列表表格单元格增加样式,便于js能定位到相应的单元格

函数定义

代表字段本身的值,

@@@代表本行记录的值,有时需要引用其它字段的值参数计算,就用@@@传递行记录的所有值 col 1.'function'=>'date("y-m-d","###")'; //将被解析为 date("y-m-d",$v['col']); 2.'function'=>'getData('a','###','@@@')';//将被解析为 getData("a",$v['col'],$v);

搜索

编辑

添加

SqlToCgfDefinition.php 根据表定义生成cgf配置文件

sql表定义解析后的数组


"title"=>[
"name"=>"title",
"zh"=>"标题",
"arrShowPage"=>
 
            ["admin"]=>
              
               "add",
               "edit",
               "list",
               "search"
       
              ["user"]=>
              
                
               "add",
               "edit",
               "list",
               "search"
           
              ["home"]=>

               "list",
               "show"
    ]     
           

1.单模块 $cgf=["base"=>['字段1'],"list"=>['字段1']]

2.多模块 $cgf['admin']=["base"=>['字段1','字段2','字段3'],"list"=>['字段1']] $cgf['user']=["base"=>['字段1','字段2','字段3'],"list"=>['字段2']] $cgf['home']=["base"=>['字段1','字段2','字段3'],"list"=>['字段3']]

不支持的功能

1.三表关联。如:订单表通过user_id关联用户表,用户表通过手机号关联所在地区表。这时想在订单列表显示用户手机号可以,但无法再关联到地区表,显示用户所在城市。

====================================================================

截图

添加页面 列表页面

下一步支持

1.字段的fuction可以区分是后端function,还是前端function. 如排序字段,后台列表希望显示出的是个可编辑的input,这样直接就能在列表页更改排序。 如果不区分的话,后台function将字段变成 ,前台列表接口sort字段获取到也是这个html,那就完完了。 所以可以用php_function表示是个后端函数,tpl_function表示模板函数,js_fuction表示js函数

如:后台商品表有display字段表示显示状态,数据库值为0,1.但在后台和用户中心希望通过函数转为文字,但返回到前台的接口,希望显示原始值,这样前端页面可以根据1或0来判断,是上架按钮,还是下架按钮。 但这种情况下,后台也需要有对应的功能。 商品名 显示状态 操作 苹果6手机 上架中(通过函数将display的值1转为文本“上架中”) 下架(通过if(dispaly==1)则显示此文字)

此时有两种办法 1.if(display=='上架') 显示下架 2.增加个display_text字段,列表展现时,显示display_text的内容 感觉都不科学

可以试播-select|1111||0:否,1:是

用命名空间和作用域解决 list.function=show 列表调用函数 search.function=show 搜索调用函数 all.function=show //默认所有,可省略 admin.list.function=show 后台列表显示调用函数

显示关联表相应字段 user_id|1111||list.table=field(username,sex)-replace //replace替换,add默认add

数组定义使用方法

公共

zh 对应字段含义

列表

1.关联表 related_table 关联表定义,相当于join related_field 关联表中对应的字段,相当于join时右表的关联字段 table_name 关联表 fields => ["state","name"], 关联表要显示的字段 "way" => "add", 展现方式, add表示左表的字段也显示,右表字段也显示。 replace表示左表字段不显示,用右表的字段代替 例: "related_table" => [ "related_field" => "issue_id", "table_name" => "goods_activity", "fields" => ["state"], "way" => "add",//replace 1.add表示显示user_id,并且增加field定义的字段 2.replace 表示用field字段替换掉user_id 'function'=>"date" ]

2.show_text 数字枚举字段,显示对应的文字含义

  1. "class"=>"c_trans_state",//给列表表格单元格增加样式,便于js能定位到相应的单元格

函数定义

代表字段本身的值,

@@@代表本行记录的值,有时需要引用其它字段的值参数计算,就用@@@传递行记录的所有值 col 1.'function'=>'date("y-m-d","###")'; //将被解析为 date("y-m-d",$v['col']); 2.'function'=>'getData('a','###','@@@')';//将被解析为 getData("a",$v['col'],$v);

搜索

编辑

添加

SqlToCgfDefinition.php 根据表定义生成cgf配置文件

sql表定义解析后的数组


"title"=>[
"name"=>"title",
"zh"=>"标题",
"arrShowPage"=>
 
            ["admin"]=>
              
               "add",
               "edit",
               "list",
               "search"
       
              ["user"]=>
              
                
               "add",
               "edit",
               "list",
               "search"
           
              ["home"]=>

               "list",
               "show"
    ]     
           

1.单模块 $cgf=["base"=>['字段1'],"list"=>['字段1']]

2.多模块 $cgf['admin']=["base"=>['字段1','字段2','字段3'],"list"=>['字段1']] $cgf['user']=["base"=>['字段1','字段2','字段3'],"list"=>['字段2']] $cgf['home']=["base"=>['字段1','字段2','字段3'],"list"=>['字段3']]