当前位置:Gxlcms > PHP教程 > CRUD生成器DBuilder设计与实现,crud生成器dbuilder_PHP教程

CRUD生成器DBuilder设计与实现,crud生成器dbuilder_PHP教程

时间:2021-07-01 10:21:17 帮助过:5人阅读

CRUD生成器DBuilder设计与实现,crud生成器dbuilder


第一章 引言

1.1 研究背景及意义

计算机软件技术发展至今,数据库已成为最广泛使用的存储格式化数据的媒介,数据库程序开发技术也日趋完善,大型的ORM框架使得数据库程序开发变得简单,并已成为操作关系型数据库的主流方式。数据库程序主要代码为CRUD(create, retrieve, update, delete)代码,随着ORM框架功能的完善,编写CRUD代码也衍生其固定的流程,对不同数据库表进行操作的CRUD代码也存在高度可重用性。当前编写重复性的CRUD代码成为开发人员的常态,不仅严重降低其积极性,而且损失其开发效率,所以迫切需要一种能够快速生成CRUD代码的产品,以期减少这方面的工作,提高开发效率。

1.2 研究现状

目前国外已经诞生一些解决上述需求的、具有很高可用性的CRUD生成器产品:CrudKit,CRUD-Admin-Generator,Dadabik,GroceryCrud,SximoBuilder。这些产品各有其特点,但也有一共同点:都是基于PHP进行开发(这在一定程度上决定于PHP语法的灵活性及其解析性)。SximoBuilder是其中的典型代表,尽管SximoBuilder设计独特、可用性高、流行度高,但也存在如下不足之处:

  • 不支持自定义表单控件;
  • 不支持多数据库;
  • 验证规则不完善,不支持异步验证;
  • 代码冗余度极大。

然而对于当今日益复杂的web程序,上述几点是开发过程必须考虑的问题,因此,开发一款既具有SximoBuilder现有功能、又完善其不足之处的CRUD生成器产品,势在必行。

1.3 研究内容

基于国内外CRUD生成器研究现状,笔者开发一款名为DBuilder(D为DataAdministrator的简写)的CRUD 生成器。

DBuilder借鉴SximoBuilder的模块为代码单元、由模板生成代码的思想,但拥有与SximoBuilder完全不同的代码生成器逻辑。它在实现SximoBuilder核心的代码生成、通用CRUD两种功能的基础上,通过重写代码逻辑完善其不足之处:代码冗余度大、缺少前端验证。

第二章 DBuilder系统分析

DBuilder面向的主要用户人群为web后台管理员以及开发人员,因此其系统分析过程,将更多的站在web后台管理员及开发人员的角度考虑问题。

2.1 需求分析

项目需要实现如下几点核心功能。

1) 数据源管理

用户可以在界面为项目配置多个数据源。配置的数据源信息包括数据库类型、地址、数据库名、端口、用户名、密码等信息。支持对数据源的增删改查,保证对数据源的增删改查不轻易造成系统问题。

2) 代码生成

此功能是DBuilder的核心要实现的功能,用户在选择数据源和数据表之后,能够对数据库表的字段做简单配置,配置包括Form表单配置、List(Table)列表配置、关系配置、全局属性配置。配置完成后DBuilder要能生成对数据库表的CRUD的MVC代码,即需要实现CRUD可用功能,但不用编写代码。

3) 数据库表CRUD

生成的代码必须支持数据表记录的新建、删除、更新、查询操作。

4) 菜单管理

DBuilder要能将生成的代码跟一个菜单项绑定,让用户点击菜单项之后,就可以使用DBuilder生成的CRUD功能。此菜单必须包括后台菜单,前台菜单不是必须的。

5) 用户管理

用户要实现多种角色。必须能够以邮箱为用户唯一标识,并作为登录参数。未来还要实现支持QQ、微信、新浪微博基于OAuth2.0的互联登录。

6) 权限管理

DBuilder要能实现不同用户角色对不同CRUD代码的执行、访问权限做到三维的可配置。譬如,现有一个文章管理的CRUD功能模块,用户角色分为系统管理员(SuperAdmin),管理员(Admin),访客(Guest),那么DBuilder要能实现如下的三维权限配置,且将之作为所有Module的默认权限。

表2-1 Module权限配置表

用户组与权限

查看

编辑

删除

导出

SuperAdmin

Admin

Guest

7) 站点参数配置

DBuilder作为一个网站的web后台程序,对站点的全局参数配置也是必须的,这些参数包括网站名字、关键词、联系地址、友情链接等等。

8) 操作日志

DBuilder要记录用户的操作信息,包括访问的页面、执行的CRUD类型、时间等等信息。日志的记录形式支持数据库和文件两种方式。

9) 多语言支持

DBuilder要支持多国语言的切换。至少应该支持中文和英语两种语言,且以中文为默认。

10) 多数据库类型支持

DBuilder要支持多种类型数据库,暂时主要支持关系型数据库,包括mysql,MS SqlServer,oracle,PostGreSQL等等。

2.2 数据原型分析

按照需求提取可得实体有:用户、用户组、数据源、代码模块、菜单,关系有:权限、日志。实体与关系的含义如下:

  • 用户:表示使用DBuilder的用户;
  • 用户组:表示用户的类型分组,用户类型应该至少包括访客、管理员、超级管理员三种;
  • 数据源:表示DBuilder包含的数据库配置,一个数据源的配置包含连接一个数据库所需的基本参数;
  • 代码模块:表示DBuilder生成的代码模块,描述了代码文件和配置;
  • 菜单:表示DBuilder的左侧菜单项;
  • 权限:表示用户组对每个代码模块的各种操作权限;
  • 日志:表示用户对每个代码模块的CRUD访问日志。

实体与关系的ER图如下:

图2-1 ER图

2.3 原则性要求

DBuilder应该要做成一套高性能、高可用的CRUD生成器,为此DBuilder设计中应该符合下面几项原则:

  • DBuilder要精确到每个数据库字段可配置;
  • 应具备一个WEB后台应用的雏形,使用户可在此基础上快速建立完整的WEB后台应用;
  • DBuilder要尽可能减少SQL操作,必要时可借助缓存、异步等技术,减少请求的处理逻辑,提高页面效率,减少用户等待时间;
  • DBuilder要有美观、简洁、直观的用户界面;
  • DBuilder要留有大量的扩展接口,能够让用户通过二次开发快速实现较为复杂的功能。

第三章 DBuilder系统设计

3.1 系统架构

DBuilder有下面2个核心的构件Core CRUD 模块和GModule,GModule对Core CRUD 模块有继承依赖的关系,GModule由MVC Code和CRUD Config组成;Core CRUD模块是手工编写的代码,而GModule是DBuilder生成的代码;Core CRUD 模块实现CRUD操作,GModule实现扩展功能。下图表示了这两个构件的组成和关系

图3-1概念与构件

下面对图中设计的概念、构件、模块关系以及Build与CRUD流程做详细阐述。

3.1.1 Core CRUD 模块

Core CRUD 模块实现核心CRUD操作,一切对GModule MVC中Controller的CRUD请求,最终转交至Core CRUD 模块进行处理。Core CRUD 模块会开放一些预处理和后处理接口交由GModule实现,这些接口会在Model,Controller,View上都有体现。

Core CRUD 模块主要包括如下文件

  • app/controllers/admin/AdminController.php
  • app/models/BaseModel.php
  • app/config/crud/admin.php
  • app/views/admin/core/list.blade.php
  • app/views/admin/core/form.blade.php

Core CRUD 模块读取GModule Configuration实现真正的CRUD操作。

3.1.2 GModule

GModule(Generated Module)不但实现了Core CRUD Module接口(MVC代码),而且具有自己配置文件(CRUD Configuration)。每一GModule表示以一张数据库表为主表,具备CRUD功能的代码文件合集(包括对应的MVC + Configuration代码)。譬如,DBuilder生成的一个GModule, 主表为core数据源user表,名字为User,那么User GModule应包含下面代码文件:

  • controllers/UserController.php
  • models/User.php
  • views/user/_list.blade.php
  • views/user/_form.blade.php
  • views/user/view.blade.php
  • config/crud/user.php

代码文件命名取决于GModule的名字,故为保证生成的代码文件不冲突,取GModule的名字(GModule Key,GModule Name)作为GModule的唯一标识。每一个GModule的信息都被保存在数据库中。一次新建 GModule操作将会新建上述所有代码文件,更新相关文件,并插入一条GModule记录到数据库。一次更新 GModule操作将只会更新Configuration文件。

GModule 由MVC代码和CRUD Configuration代码组成,下面分别进行阐述:

  • MVC代码:用来实现扩展接口。CRUD请求应最先路由到GModule MVC的中的Controller(控制器)。并且GModule MVC 应与Core CRUD Module的MVC代码有继承关系。
  • CRUD Configuration代码:实现对GModule主表增删改查参数的配置。该文件放置在app/config/crud/目录下,以php array的格式定义。它包含对所有字段的表单,列表,视图,关系等参数的配置,以及全局的参数配置。

GModule并不表示具体某一个模块,而是代指一类模块,这种模块可以由DBuilder生成,或者由开发人员手工建立。它主要用来实现Core CRUD Module的接口,主要包括下述几部分

1) Controller接口

假设GModule模块的 Controller为A,Core CRUD Module 的Controller为B,则A应继承自B。CRUD请求会先路由到A,而实际的处理者是B。A会实现B开放的下列接口。

  • beforeListExcuteQuery(&querier):该接口在List查询器执行查询之前调用,传递的参数为查询器引用。用来在查询之前,绑定特殊的查询参数。
  • beforeList(&data):该接口在List查询器执行之后,渲染List视图之前调用。传递的参数为视图参数引用,其中包括查询出的model集合。用来对查询的model 集合做后处理,或者对list视图绑定一些Module专有的参数。
  • beforeEditExcuteQuery(&querier):该接口在Edit请求中Model查询器执行查询之前调用,传递的是查询器引用。用来绑定查询model需要的特殊参数。
  • beforeEdit(&data):该接口在Edit中Model查询器执行之后,渲染视图之前调用,传递的是视图参数引用,其中包括查询器查询出的model。用来做渲染前的预处理。
  • afterSave(&model):该接口在Edit中,保存编辑的之后调用,传递的是保存在数据库中,最新的数据库记录持久化的model。用来对model做一些复杂的后级联处理。
  • beforeView(data): 该接口在View请求中,View 查询器查询之后调用,传递的是视图参数的引用。用来对视图显示做预处理。

2) Model 接口

GModule MVC代码中的Model也继承自BaseModel,实现 BaseModel类开放的一些接口可以完成扩展。

formatXXXAttribute():该接口用来格式化某个字段。本产品基于Laravel,其已经具备类似的接口,就是getXXXXAttribute()。但这样的接口的优先级比字段优先级高,这在特殊的情况下为开发带来了不便,所以再设计一个类似的接口,该接口的优先级低于字段本身。

3) View 接口

视图的扩展接口与前两者不同,主要体现在子视图与视图块上,也就是在Core CURD模块的视图基础上,扩展视图组件。默认Core CRUD MVC视图生成的是一个表格或者一个表单,占满页面。而View接口将提供在该表格上下左右扩展页面组件的能力。

4) Configuration

每一个GModule对应一个Configuration文件,其中包含GModule对主表各个字段的配置参数,以及布局参数。

3.1.3 模块关系

CRUD请求路由到GModule的Controller,GModule代码实现Core CRUD MVC开放的接口,而由Core CRUD Module去真正实现对数据库的CRUD操作。每一个GModule的信息应该被记录在数据库表中,以便给GModule关联菜单,控制权限,记录操作日志等等。一些主要模块之间的关系如下图所示。

图3-2模块关系

从图2-2中可以看到,由GModule管理模块根据用户配置来生成一个GModule A,当用户的CRUD请求到达GModule A时,GModule 会讲请求转交Core CRUD进行处理,Core CRUD 模块再以SQL对数据库进行CRUD操作。

3.1.4 Build 与 CRUD流程

DBuilder项目的方案,将真正的CRUD操作交给了Core CRUD Module去执行,CRUD参数由GET或者POST请求参数与GModule Configuration构成,而GModule的MVC代码只是去实现Core CRUD MVC开放的一些预处理或者后处理接口。

图2-3是DBuilder最核心的流程图,包含Module的生成和处理CRUD请求的过程,图2-4是SximoBuilder 中Module的生成和处理CRUD请求的流程图。

图3-3 DBuilder 代码生成和处理CRUD的流程

图3-4 SximoBuilder 代码生成和处理CRUD的流程

对比两者,可以看到两者的最大区别,是DBuilder复用一份CRUD代码,而不是像Sximo那样为每一个Module生成一套可以当独执行的CRUD代码。这样做的好处是提高了复用性,并通过Module CRUD MVC实现预处理/后处理接口达到扩展性的目的。

3.2 Core数据源

Core数据源是DBuilder的默认数据源,其类型为mysql,数据库名为dbuilder,本节按照《数据原型分析》一节进行详细的数据库设计。为提高程序性能,数据源信息保存在代码文件app/config/datasource.php中,文件内容如下:

'core' =>

array (

'driver' => 'mysql',

'host' => 'localhost',

'database' => 'dbuilder',

'username' => 'root',

'password' => 'root',

'charset' => 'utf8',

'collation' => 'utf8_unicode_ci',

'prefix' => '',

'edit' => false,

'port' => 3306,

),

// more data source

);

其中Core数据源有下述数据表:

1) d_menu 表:表示后台左侧树形菜单,每一个可点击跳转的菜单项必须与一个Module进行关联。

表3-1 web后台左侧菜单表

field

type

default

info

id

int

auto_increment

PRI

module_id

int

module_name

varchar(12)

parent_id

null

父菜单项

title

varchar(12)

module_title

显示名称

_order

int

0

排序字段

2) d_module 表:记录了module信息,每一条d_module表的记录代表了DBuilder生成的一个Module。

表3-2 module信息描述

field

type

default

info

id

int

auto_increment

PRI

name

varchar(32)

UIN

title

varchar(32)

module标题

note

varchar(32)

module 说明

db_source

varchar(16)

core

数据源名称

db_table

varchar(16)

module主表

db_table_key

varchar(16)

主表PRI

3) d_user 表:保存着使用后台程序的用户。

表3-3 web后台用户

field

type

default

info

id

int

auto_increment

PRI

username

varhcar(64)

用户名

email

varchar(64)

邮箱

password

varchar(64)

HASH

salt

varchar(64)

last_login

timestamp

最后登录时间

remember_token

记住密码口令

group_id

int

组ID

4) d_group表:表示对后台用户的分组信息。

表3-4 用户分组表

field

type

default

info

id

int

auto_increment

PRI

name

varhcar(64)

组名

note

varchar(128)

组说明

level

int

组级别

5) d_group_access表:记录了每个GModule、不同后台用户组与各种操作权限的三维权限信息。

表3-5 用户组对Module权限表

field

type

default

info

id

int

auto_increment

PRI

group_id

int

组id

module_id

int

Module模块ID

edit

int

1

可编辑

view

int

1

可查看

delete

int

1

可删除

export

int

1

可导出

6) d_log表:记录了每个用户的操作日志。

表3-6 用户操作日志

field

type

default

info

id

int

auto_increment

PRI

user_id

int

用户id

ip_addr

varchar(15)

客户端IP

module_id

int

访问的moduleid

module_title

varchar(16)

task

varchar(16)

操作

created_at

timestamp

可导出

3.3 数据源管理模块

DBuilder需要支持多数据源,多种类型数据库。数据源信息保存在d_database表中。考虑到数据库操作是频繁操作,如果将数据源信息保存在数据库中,则每次数据库操作将多一次数据源查询操作,这样做浪费性能。那么DBuilder不应该把数据源信息保存在数据库中,而应该保存在代码文件中。数据源管理的信息包括数据源名称(数据源的唯一标识,DBuilder默认的数据源名为core)、数据库类型、地址、端口、数据库名、用户名、密码等等信息。因为数据源管理模块并不对表进行增删改查操作,所以数据源管理模块并不是一个GModule模块。该模块的代码完全手工编写。

3.4 GModule 管理模块

DBuilder将以基于名字为“Module”的GModule作为生成GModule的用户接口,该模块称作GModule管理模块,换言之GModule管理模块本身就是一个GModule,该GModule的主表即是core数据源中保存GModule信息的数据库表,改GModule的名字为“Module”。GModule 管理模块包含创建,更新和删除GModule 的所有代码文件以及数据库记录。GModule的新建和删除需要更新全局的GModule路由。

1) GModule 路由

GModule路由定义在一个独立的代码文件中,为一个以GModule名字进行减号分词并全部小写的字符串为键(譬如:GModule名字为OrderItem,则键值为order-item)、以Module中Controller类的类名为值的map字典,GModule路由是全局的。

2) GModule 新建&更新

新建GModule将在数据库中生成一条记录、生成所有的module文件、并更新路由。更新操作只修改配置文件。新建与更新都使用相同的编辑视图,此编辑视图是对GModule Configuration的图形化配置界面。

3) GModule 删除

GModule删除将删除所有的GModule MVC代码,删除GModule Configuration代码,删除数据库表记录,并更新GModule路由。

3.5 Core CRUD 模块

Core CRUD 模块是DBuilder处理CRUD请求的实际处理者,它由下述几部分组成:

1) 参数解析初始化

初始化Model,实例化一个Module的Model对象作为初始化查询器。加载Module Configuration,对未设置的值进行设置默认值,对参数进行汇聚。

2) 表单Form

主要包括新建和更新功能。根据GModule主表主键primaryKey是否设置判断是新建还是更新操作。下图是Form模块的流程

图3-5 Form执行流程

Form 分两部分,第一部分渲染Form页面给用户填写。第二部分为Form保存。

渲染Form页面需要考虑的有Form控件和有外键关系的字段要怎么处理。Form控件需要支持类型包括text、text_date、text_datetime、textarea、select、radio、checkbox、file、hidden、address以及custom,自定义控件应该继承FormControl类,自定义控件的渲染由控件的render方法完成。Form渲染需要判断有关系的字段做辅助加载。比如对post(文章)表进行编辑,post表有一个字段为category_id,表示文章的栏目ID,对应category(栏目)表的id字段。这时需要对category_id使用select,radio,checkbox控件进行加载,方便用户输入。比如使用select控件,那么应该将category.id作为option的value,将category.name作为option中的text。这样做也是为了方便用户输入。此步骤与List中搜索时有共性,因此代码可复用。

Form 保存需要考虑一些自定义控件的保存,自定义控件的数保存由自定义控件类的onSave方法完成。Form 保存还需要考虑关系的保存,默认应该级联更新附属表。Form 表单在用户输入完成点击保存之后,要分下面几步:

  • 根据字段配置的验证规则进行验证;
  • 应判断Module Configuration 中的relation进行分析,进行必要的级联操作;
  • 并要调用自定义控件的onSave方法;
  • 最后才应更新或新建主表数据;
  • 跳转:更新或新建成功跳转至List,失败跳转至Form。

Form 还需要开放对应的预处理和后处理接口。

3) 列表List(Table)

List是一个分页Table,按照Module Configuration 中的字段配置显示分页数据。支持列表搜索,排序,勾选删除,导出等功能;

  • 分页展现数据以InitQuerier模块得到的Model作为查询器,结合分页,查询出基本的数据列表。分页类型为全页刷新类型(非异步分页);
  • List搜索:支持在Module Configuration中定义了search不等于false的字段作为搜索条件。搜索关系为逻辑与的关系。并反映在GET参数上。搜索输入控件根据字段的form type来定。在Form 中定义为select,radio,checkbox控件的字段,在List中都将使用select控件作为输入控件;
  • List 排序:以在Module Configuration中定义了form.sort 不等于 false的字段作为可排序字段。排序只支持按单一字段排序,降序方式含升序和降序;
  • List 多选操作主要支持多选删除,多选复制操作,任何删除操作都需确认;
  • List 数据每行记录的支持的操作按Module Configuration中的配置给出,默认支持编辑,删除,查看三项操作;
  • List 也要开放预处理/后处理接口给Module CRUD MVC。

4) 查看View

View 暂时以Form为基础,提供预处理后处理接口,但不允许编辑。

第四章 DBuilder系统实现

4.1 目录结构

代码按照前段资源、MVC、Configuration、Library等概念进行了分目录存放。下面表格中给出了主要目录的说明:

表4-2 代码主要目录

目录

作用

assets

此目录存放着各种各样的前端资源。包括bootstrap,以及自定义的css和js文件。

plugins

存放特殊前端插件的目录,比如富文本编辑器,视音频插件等等。

app/controllers/admin

存放着MVC中控制器的目录。其中,DBuilder的核心在admin目录下。

app/models

存放着MVC中模型(Model)的目录。用来做数据库查询用。

app/views

存放着MVC中视图的目录。文件名以*.blade.php的格式命名。

app/library

存放PHP辅助类,PHP库的目录。

app/config/crud

存放Module Configuration的目录。

4.2 GModule 配置文件

GModule配置文件定义了GModule的参数,该文件保存在app/config/crud/下,是以GModule Name进行蛇形分词得到的字符串命名的php文件(譬如:一GModule的名字为OrderItem,则GModule配置文件为order_item.php)。配置参数以数组格式返回。

考虑到PHP数组在表格中呈现的美观性,对参数以配置中的Key=>Value形式,以点分形式Key.Value表示。

表4-3 root配置

Configuration Key

类型

默认值

含义

fields

array

array()

字段列表

fields.field_name

array

array()

对field_name字段的配置

fields.field_name.label

string

UP(field_name)

显示在列表表格的表头的内容,和form控件旁边的内容

fields.field_name.form

array

array()

field_name字段的表单配置,具体参考

fields.field_name.form配置

fields.field_name.list

array

array()

field_name 字段的列表配置,具体参考

fields.field_name.list配置

fields.field_name. relation

array

array()

field_name 字段的关系

表4-3中每个字段的表单配置说明如下表所示:

表4-4 fields.field_name.form配置

Configuration Key

值类型

默认

含义

type

string

text

Form控件类型

show

bool

true

是否出现在表单

hidden

bool

false

是否以隐藏的空间在表单中

rule

string

required

验证规则

ajax_validate

bool

false

是否异步验证

placeholder

string

控件中的提示

表4-3中每个字段的列表配置说明如下表所示:

表4-5 fields.field_name.list配置

Configuration Key

值类型

默认

含义

show

bool

true

是否出现在表单

sort

bool

true

字段是否可以排序,默认可排序

search

bool,array

array()

是否可搜索以及搜索规则

string

控件中的提示

表4-3中每个字段的关系配置说明如下表所示:

表4-6 fields.field_name.relation配置

Configuration Key

值类型

默认

含义

table

string

关联表

foreign_key

string

id

对应关联表里的字段

show

string

关联表里的一个字段,当需要转义时,将用该字段代替field_nae字段显示

as

string

table_show

转义查询出的值用哪个字段表示,主要为了防止主表和关联表有重复字段

下面是一个名为post的GModule的Configuration文件

1 return array ( 2 'data_source' => 'core', 3 'table' => 'post', 4 'fields' => 5 array ( 6 'id' => 7 array ( 8 'label' => 'ID', 9 'form' => 10 array ( 11 'show' => true, 12 'hidden' => true, 13 'type' => 'text', 14 'rule' => 'required', 15 'ajax_validate' => false, 16 'placeholder' => '', 17 ), 18 'list' => 19 array ( 20 'show' => true, 21 'sort' => true, 22 'search' => '=', 23 'lookup' => false, 24 ), 25 'relation' => 26 array ( 27 'type' => '', 28 'table' => '', 29 'foreign_key' => '', 30 'show' => '', 31 'as' => '', 32 ), 33 ), 34 'title' => 35 array ( 36 'label' => '标题', 37 'form' => 38 array ( 39 'show' => true, 40 'hidden' => false, 41 'type' => 'text', 42 'rule' => 'required', 43 'ajax_validate' => false, 44 'placeholder' => '', 45 ), 46 'list' => 47 array ( 48 'show' => true, 49 'sort' => true, 50 'search' => '=', 51 'lookup' => false, 52 ), 53 'relation' => 54 array ( 55 'type' => '', 56 'table' => '', 57 'foreign_key' => '', 58 'show' => '', 59 'as' => '', 60 ), 61 ), 62 'short' => 63 array ( 64 'label' => '摘要', 65 'form' => 66 array ( 67 'show' => true, 68 'hidden' => false, 69 'type' => 'textarea', 70 'rule' => 'required', 71 'ajax_validate' => false, 72 'placeholder' => '', 73 ), 74 'list' => 75 array ( 76 'show' => true, 77 'sort' => true, 78 'search' => '=', 79 'lookup' => false, 80 ), 81 'relation' => 82 array ( 83 'type' => '', 84 'table' => 'category', 85 'foreign_key' => 'id', 86 'show' => 'id', 87 'as' => '', 88 ), 89 ), 90 'content' => 91 array ( 92 'label' => '正文', 93 'form' => 94 array ( 95 'show' => true, 96 'hidden' => false, 97 'type' => 'wysiwyg', 98 'rule' => 'required', 99 'ajax_validate' => false, 100 'placeholder' => '', 101 ), 102 'list' => 103 array ( 104 'show' => false, 105 'sort' => true, 106 'search' => '=', 107 'lookup' => false, 108 ), 109 'relation' => 110 array ( 111 'type' => '', 112 'table' => 'category', 113 'foreign_key' => 'id', 114 'show' => 'id', 115 'as' => '', 116 ), 117 ), 118 'view_ct' => 119 array ( 120 'label' => '查看次数', 121 'form' => 122 array ( 123 'show' => false, 124 'hidden' => false, 125 'type' => 'text', 126 'rule' => 'required', 127 'ajax_validate' => false, 128 'placeholder' => '', 129 ), 130 'list' => 131 array ( 132 'show' => true, 133 'sort' => true, 134 'search' => '=', 135 'lookup' => false, 136 ), 137 'relation' => 138 array ( 139 'type' => '', 140 'table' => '', 141 'foreign_key' => '', 142 'show' => '', 143 'as' => '', 144 ), 145 ), 146 'created_at' => 147 array ( 148 'label' => '创建时间', 149 'form' => 150 array ( 151 'show' => false, 152 'hidden' => false, 153 'type' => 'text', 154 'rule' => 'required', 155 'ajax_validate' => false, 156 'placeholder' => '', 157 ), 158 'list' => 159 array ( 160 'show' => false, 161 'sort' => true, 162 'search' => '=', 163 'lookup' => false, 164 ), 165 'relation' => 166 array ( 167 'type' => '', 168 'table' => '', 169 'foreign_key' => '', 170 'show' => '', 171 'as' => '', 172 ), 173 ), 174 'updated_at' => 175 array ( 176 'label' => '更新时间', 177 'form' => 178 array ( 179 'show' => false, 180 'hidden' => false, 181 'type' => 'text', 182 'rule' => 'required', 183 'ajax_validate' => false, 184 'placeholder' => '', 185 ), 186 'list' => 187 array ( 188 'show' => true, 189 'sort' => true, 190 'search' => '=', 191 'lookup' => false, 192 ), 193 'relation' => 194 array ( 195 'type' => '', 196 'table' => '', 197 'foreign_key' => '', 198 'show' => '', 199 'as' => '', 200 ), 201 ), 202 'category_id' => 203 array ( 204 'label' => '栏目', 205 'form' => 206 array ( 207 'show' => true, 208 'hidden' => false, 209 'type' => 'select', 210 'rule' => 'required', 211 'ajax_validate' => false, 212 'placeholder' => '', 213 ), 214 'list' => 215 array ( 216 'show' => true, 217 'sort' => true, 218 'search' => '=', 219 'lookup' => false, 220 ), 221 'relation' => 222 array ( 223 'type' => 'belongsTo', 224 'table' => 'category', 225 'foreign_key' => 'id', 226 'show' => 'title', 227 'as' => 'category_title', 228 ), 229 ), 230 ), 231 'list_options' => 232 array ( 233 'page' => 10, 234 'create' => true, 235 'update' => true, 236 'delete' => true, 237 ), 238 'form_options' => 239 array ( 240 'layout' => 241 array ( 242 'cols' => 12, 243 'label_cols' => 1, 244 'input_cols' => 11, 245 ), 246 ), 247 'relations' => 248 array ( 249 'id' => 250 array ( 251 'type' => '', 252 'table' => '', 253 'foreign_key' => '', 254 'show' => '', 255 'as' => '', 256 ), 257 'title' => 258 array ( 259 'type' => '', 260 'table' => '', 261 'foreign_key' => '', 262 'show' => '', 263 'as' => '', 264 ), 265 'short' => 266 array ( 267 'type' => '', 268 'table' => '', 269 'foreign_key' => '', 270 'show' => '', 271 'as' => '', 272 ), 273 'content' => 274 array ( 275 'type' => '', 276 'table' => '', 277 'foreign_key' => '', 278 'show' => '', 279 'as' => '', 280 ), 281 'view_ct' => 282 array ( 283 'type' => '', 284 'table' => '', 285 'foreign_key' => '', 286 'show' => '', 287 'as' => '', 288 ), 289 'created_at' => 290 array ( 291 'type' => '', 292 'table' => '', 293 'foreign_key' => '', 294 'show' => '', 295 'as' => '', 296 ), 297 'updated_at' => 298 array ( 299 'type' => '', 300 'table' => '', 301 'foreign_key' => '', 302 'show' => '', 303 'as' => '', 304 ), 305 'category_id' => 306 array ( 307 'type' => '', 308 'table' => '', 309 'foreign_key' => '', 310 'show' => '', 311 'as' => '', 312 ), 313 ), 314 ); GModule Configuration

4.3 数据源管理模块实现

数据源管理模块完成基于网页界面对app/config/datasource.php文件的配置。包含数据源列表页,数据源新建与编辑页。

  • 数据源列表页:对应请求路径为admin/data-source/list,此页面读取DataSource文件渲染List(table)页面,密码不显示。
  • 数据源编辑页面:对应请求路径为 admin/data-source/edit,GET请求读取DataSource问价内容渲染表单,POST请求将数据源参数输出值DataSource文件。此页面提供测试连接功能,实现方法为基于表单的数据源参数连接数据库,执行一条SQL语句,连接是否成功取决于SQL是否执行成功。

实现数据源管理的核心控制器代码放在DataSourceController.php文件中。

1 php 2 /** 3 * Created by PhpStorm. 4 * User: lvyahui 5 * Date: 2016/5/12 6 * Time: 15:35 7 */ 8 9 namespace admin; 10 11 use BaseModel; 12 use Illuminate\Support\Facades\Config; 13 use Illuminate\Support\Facades\Redirect; 14 use SiteHelpers; 15 use Illuminate\Support\Facades\Response; 16 use Illuminate\Support\Facades\Input; 17 18 use PDOException; 19 use PDO; 20 class DataSourceController extends AdminController 21 { 22 /** 23 * 呈现数据源列表 24 */ 25 public function getList() 26 { 27 $datasources = SiteHelpers::loadDataSources(); 28 $this->makeView(array( 29 'datasources' => $datasources, 30 )); 31 } 32 33 /** 34 * 异步加载某数据源的所有数据表 35 * @return \Illuminate\Http\JsonResponse 36 */ 37 public function getTables() 38 { 39 $dataSourceName = Input::get("data_source"); 40 $dataSources = SiteHelpers::loadDataSources(); 41 42 $dataSource = $dataSources[$dataSourceName]; 43 $tables = BaseModel::getTableList($dataSource['database'], $dataSourceName); 44 return Response::json(array( 45 'success' => true, 46 'data' => array( 47 'tables' => $tables, 48 'selected' => Input::get('table'), 49 ), 50 )); 51 } 52 53 /** 54 * 呈现数据源编辑或者新建FORM 55 * @param null $slug 56 */ 57 public function getEdit($slug = null) 58 { 59 $dataSource = null; 60 if ($slug) { 61 // 更新 62 $dataSource = $slug === 'core' ? Config::get('database.connections.core') 63 : Config::get('datasource.' . $slug); 64 $dataSource['name'] = $slug; 65 } else { 66 // 新建 67 $dataSource = array( 68 'name' => '', 69 'driver' => 'mysql', 70 'host' => 'localhost', 71 'port' => 3306, 72 'database' => '', 73 'username' => 'root', 74 'password' => '', 75 'charset' => 'utf8', 76 'collation' => 'utf8_unicode_ci' 77 ); 78 } 79 80 $this->makeView(array( 81 'dataSource' => $dataSource 82 )); 83 } 84 85 /** 86 * 测试数据源连接是否可靠 87 * @return \Illuminate\Http\JsonResponse 88 */ 89 public function postTest(){ 90 $success = true; 91 try{ 92 $dsn = Input::get('driver').':'.Input::get('host').':'.Input::get('port').';dbname='.Input::get('database'); 93 $dbh = new \PDO($dsn,Input::get('username'),Input::get('password')); 94 // $connection = new Connection($dbh,Input::get('database')); 95 // $key = md5(date("Y-m-d H:i:s")); 96 // DB::addConnection($key,$connection); 97 // if(!DB::connection($key)->getDatabaseName()){ 98 // $success = false; 99 // } 100 $dbh = null; 101 }catch(PDOException $e){ 102 $success = false; 103 } 104 return Response::json(array( 105 'success' => $success, 106 )); 107 } 108 109 /** 110 * 保存编辑好的数据源信息 111 * @param null $primaryKeyValue 112 * @return mixed 113 */ 114 public function postEdit($primaryKeyValue = null) 115 { 116 $dataSources = SiteHelpers::loadDataSources(); 117 $name = Input::get('name'); 118 $dataSources[$name] = Input::all(); 119 SiteHelpers::saveDataSources($dataSources); 120 121 return Redirect::action(get_class($this).'@getList'); 122 } 123 124 125 public function getTableFields(){ 126 $connection = Input::get('connection'); 127 $table = Input::get('table'); 128 129 $rawFields = BaseModel::getTableColumns($table,$connection); 130 131 $fields = array(); 132 $pri = null; 133 foreach($rawFields as $field){ 134 if($field->Key === 'PRI'){ 135 $pri = $field->Field; 136 } 137 $fields

人气教程排行