With the development of computer software technology, databases have become the most widely used medium for storing formatted data, and database program development technology has also become increasingly perfect. Large-scale ORM frameworks have made database program development simple, and have become the basis for operating relational databases. mainstream approach. The main code of the database program is CRUD (create, retrieve, update, delete) code. With the improvement of the ORM framework function, writing CRUD code also derives its fixed process. CRUD code that operates on different database tables is also highly reusable. . Currently, writing repetitive CRUD codes has become the norm for developers, which not only seriously reduces their enthusiasm, but also reduces their development efficiency. Therefore, there is an urgent need for a product that can quickly generate CRUD codes in order to reduce this work and improve development efficiency.
At present, some CRUD generator products with high usability that solve the above needs have been produced abroad: CrudKit, CRUD-Admin-Generator, Dadabik, GroceryCrud, SximoBuilder. Each of these products has its own characteristics, but they also have one thing in common: they are all developed based on PHP (this is determined to a certain extent by the flexibility and parsing of PHP syntax). SximoBuilder is a typical representative. Although SximoBuilder has a unique design, high usability, and high popularity, it also has the following shortcomings:
However, for today's increasingly complex web programs, the above points are issues that must be considered during the development process. Therefore, it is imperative to develop a CRUD generator product that not only has the existing functions of SximoBuilder but also improves its shortcomings. OK.
Based on the current research status of CRUD generators at home and abroad, the author developed a CRUD generator called DBuilder (D is the abbreviation of DataAdministrator).
DBuilder draws on SximoBuilder’s idea that modules are code units and code is generated from templates, but it has a code generator logic that is completely different from SximoBuilder. On the basis of realizing the core code generation and general CRUD functions of SximoBuilder, it improves its shortcomings by rewriting the code logic: large code redundancy and lack of front-end verification.
The main user groups of DBuilder are web backend administrators and developers, so its system analysis process will consider issues more from the perspective of web backend administrators and developers.
The project needs to implement the following core functions.
1) Data source management
Users can configure multiple data sources for the project in the interface. The configured data source information includes database type, address, database name, port, user name, password and other information. Supports addition, deletion, modification and query of data sources to ensure that addition, deletion, modification and query of data sources will not easily cause system problems.
2) Code generation
This function is the core function of DBuilder. After selecting the data source and data table, the user can simply configure the fields of the database table. The configuration includes Form configuration, List (Table) list configuration, relationship configuration, Global property configuration. After the configuration is completed, DBuilder must be able to generate CRUD MVC code for the database table, that is, it needs to implement the CRUD available functions, but there is no need to write code.
3) DatabaseTable CRUD
The generated code must support the creation, deletion, update, and query operations of data table records.
4) Menu Management
DBuilder must be able to bind the generated code to a menu item, so that after the user clicks on the menu item, they can use the CRUD function generated by DBuilder. This menu must include the background menu, the front menu is not required.
5) User Management
Users need to implement multiple roles. It must be possible to use the email address as a unique identifier for the user and as a login parameter. In the future, we will also implement support for QQ, WeChat, and Sina Weibo's interconnected login based on OAuth2.0.
6) Permission Management
DBuilder must be able to implement three-dimensional configurability of the execution and access rights of different CRUD codes for different user roles. For example, there is a CRUD function module for article management. The user roles are divided into system administrator (SuperAdmin), administrator (Admin), and guest (Guest). Then DBuilder must be able to implement the following three-dimensional permission configuration and use it as all Module's default permissions.
Table 2-1 Module permission configuration table
用户组与权限 |
查看 |
编辑 |
删除 |
导出 |
SuperAdmin |
√ |
√ |
√ |
√ |
Admin |
√ |
√ |
√ |
|
Guest |
√ |
|
|
|
7) Site parameter configuration
DBuilder, as a web background program for a website, is also necessary to configure the global parameters of the site. These parameters include website name, keywords, contact address, friendly links, etc.
8) Operation log
DBuilder should record the user's operation information, including the pages visited, CRUD type executed, time and other information. The log recording format supports two methods: database and file.
9) Multiple language support
DBuilder should support switching between multiple languages. At least two languages, Chinese and English, should be supported, with Chinese as the default.
10) Multiple database types supported
DBuilder should support multiple types of databases, and currently mainly supports relational databases, including mysql, MS SqlServer, oracle, PostGreSQL, etc.
The entities available for extraction according to requirements include: users, user groups, data sources, code modules, menus, and relationships: permissions and logs. The meanings of entities and relationships are as follows:
The ER diagram of entities and relationships is as follows:
Figure 2-1 ER diagram
DBuilder should be made into a high-performance, highly available CRUD generator. To this end, the design of DBuilder should comply with the following principles:
DBuilder has the following two core components: Core CRUD module and GModule. GModule has an inheritance dependency relationship on the Core CRUD module. GModule is composed of MVC Code and CRUD Config; the Core CRUD module is manually written code, and GModule is the code generated by DBuilder; the Core CRUD module implements CRUD operations, and GModule implements extended functions. The figure below shows the composition and relationship of these two components
Figure 3-1 Concept and components
The following is a detailed explanation of the concepts, components, module relationships, and Build and CRUD processes designed in the figure.
The Core CRUD module implements core CRUD operations. All CRUD requests to the Controller in GModule MVC are eventually transferred to the Core CRUD module for processing. The Core CRUD module will open some pre-processing and post-processing interfaces for GModule to implement. These interfaces will be reflected in Model, Controller and View.
Core CRUD module mainly includes the following files
Core CRUD module reads GModule Configuration to implement real CRUD operations.
GModule (Generated Module) not only implements the Core CRUD Module interface (MVC code), but also has its own configuration file (CRUD Configuration). Each GModule represents a database table as the main table and a collection of code files with CRUD functions (including the corresponding MVC Configuration code) . For example, a GModule generated by DBuilder, the main table is the core data source user table, and the name is User, then the User GModule should contain the following code file:
The naming of the code file depends on the name of the GModule. Therefore, in order to ensure that the generated code files do not conflict, the name of the GModule (GModule Key, GModule Name) is used as the unique identifier of the GModule. The information of each GModule is saved in the database. A new GModule operation will create all the above code files, update related files, and insert a GModule record into the database. An update GModule operation will only update the Configuration file.
GModule consists of MVC code and CRUD Configuration code, which are explained below:
GModule does not represent a specific module, but refers to a type of module, which can be generated by DBuilder or manually created by developers. It is mainly used to implement the interface of Core CRUD Module, mainly including the following parts
1) Controller interface
Assume that the Controller of the GModule module is A and the Controller of the Core CRUD Module is B, then A should inherit from B. The CRUD request will be routed to A first, and the actual handler is B. A will implement the following interfaces opened by B.
2) Model interface
The Model in the GModule MVC code also inherits from BaseModel, and can be extended by implementing some interfaces opened by the BaseModel class.
formatXXXAttribute(): This interface is used to format a certain field. This product is based on Laravel, which already has a similar interface, which is getXXXXAttribute(). However, the priority of such an interface is higher than that of the field, which brings inconvenience to development in special cases, so a similar interface is designed with a lower priority than the field itself.
3) View interface
The extension interface of the view is different from the previous two, which is mainly reflected in the subview and view block, that is, based on the view of the Core CURD module, the view component is extended. By default, the Core CRUD MVC view generates a table or form that fills the page. The View interface will provide the ability to expand page components up, down, left, and right on the table.
4) Configuration
Each GModule corresponds to a Configuration file, which contains the GModule's configuration parameters for each field of the main table, as well as layout parameters.
CRUD requests are routed to the Controller of GModule. The GModule code implements the open interface of Core CRUD MVC, and the Core CRUD Module actually implements the CRUD operation on the database. The information of each GModule should be recorded in the database table in order to give the GModule associated menus, control permissions, record operation logs, etc. The relationship between some major modules is shown in the figure below.
Figure 3-2 Module Relationship
As can be seen from Figure 2-2, the GModule management module generates a GModule A according to the user configuration. When the user's CRUD request reaches GModule A, GModule will transfer the request to Core CRUD for processing, and the Core CRUD module will then Perform CRUD operations on the database with SQL.
The solution of the DBuilder project hands over the real CRUD operations to the Core CRUD Module for execution. The CRUD parameters are composed of GET or POST request parameters and GModule Configuration, and the MVC code of GModule is only to implement some of the prerequisites opened by Core CRUD MVC. Processing or post-processing interface.
Figure 2-3 is the core flow chart of DBuilder, including the process of generating Modules and processing CRUD requests. Figure 2-4 is the flow chart of generating Modules and processing CRUD requests in SximoBuilder.
Figure 3-3 DBuilder code generation and CRUD processing process
Figure 3-4 SximoBuilder code generation and CRUD processing process
Comparing the two, you can see that the biggest difference between the two is that DBuilder reuses a CRUD code instead of generating a set of CRUD codes for each Module that can be executed independently like Sximo does. The advantage of this is that it improves reusability and achieves scalability through the pre-processing/post-processing interface through Module CRUD MVC.
Core data source is the default data source of DBuilder. Its type is mysql and the database name is dbuilder. This section will conduct detailed database design according to the "Data Prototype Analysis" section. In order to improve program performance, data source information is stored in the code file app/config/datasource.php. The file content is as follows:
array ( 'driver' => 'mysql',
|
field<🎜> |
type<🎜> |
default<🎜> |
info<🎜> |
<🎜>id<🎜> | <🎜>int<🎜> | <🎜>auto_increment<🎜> | <🎜>PRI<🎜> |
<🎜>module_id<🎜> | <🎜>int<🎜> | <🎜> <🎜> | <🎜> <🎜> |
<🎜>module_name<🎜> | <🎜>varchar(12)<🎜> | <🎜> <🎜> | <🎜> <🎜> |
<🎜>parent_id<🎜> | <🎜> <🎜> | <🎜>null<🎜> | <🎜>Parent menu item<🎜> |
<🎜>title<🎜> | <🎜>varchar(12)<🎜> | <🎜>module_title<🎜> | <🎜>Display name<🎜> |
<🎜>_order<🎜> | <🎜>int<🎜> | <🎜>0<🎜> | <🎜>Sort field<🎜> |
2) D_module table: records module information. Each record in the d_module table represents a Module generated by DBuilder.
Table 3-2 module information description
|
type
|
default
|
info |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id |
|
<🎜>auto_increment<🎜> | <🎜>PRI<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>name<🎜> | <🎜>varchar(32)<🎜> | <🎜> <🎜> | <🎜>UIN<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>title<🎜> | <🎜>varchar(32)<🎜> | <🎜> <🎜> | <🎜>module title<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>note<🎜> | <🎜>varchar(32)<🎜> | <🎜> <🎜> | <🎜>module description<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>db_source<🎜> | <🎜>varchar(16)<🎜> | <🎜>core<🎜> | <🎜>Data source name<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>db_table<🎜> | <🎜>varchar(16)<🎜> | <🎜> <🎜> | <🎜>module main table<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>db_table_key<🎜> | <🎜>varchar(16)<🎜> | <🎜> <🎜> | <🎜>Main table PRI<🎜> |
<🎜>field<🎜> | <🎜>type<🎜> | <🎜>default<🎜> | <🎜>info<🎜> |
<🎜>id<🎜> | <🎜>int<🎜> | <🎜>auto_increment<🎜> | <🎜>PRI<🎜> |
<🎜>username<🎜> | <🎜>varhcar(64)<🎜> | <🎜> <🎜> | <🎜>Username<🎜> |
<🎜>email<🎜> | <🎜>varchar(64)<🎜> | <🎜> <🎜> | <🎜>Email<🎜> |
<🎜>password<🎜> | <🎜>varchar(64)<🎜> | <🎜> <🎜> | <🎜>HASH<🎜> |
<🎜>salt<🎜> | <🎜>varchar(64)<🎜> | <🎜> <🎜> | <🎜>Salt<🎜> |
<🎜>last_login<🎜> | <🎜>timestamp<🎜> | <🎜> <🎜> | <🎜>Last login time<🎜> |
<🎜>remember_token<🎜> | <🎜> <🎜> | <🎜> <🎜> | <🎜>Remember the password<🎜> |
<🎜>group_id<🎜> | <🎜>int<🎜> | <🎜> <🎜> | <🎜>Group ID<🎜> |
<🎜>field<🎜> | <🎜>type<🎜> | <🎜>default<🎜> | <🎜>info<🎜> |
<🎜>id<🎜> | <🎜>int<🎜> | <🎜>auto_increment<🎜> | <🎜>PRI<🎜> |
<🎜>name<🎜> | <🎜>varhcar(64)<🎜> | <🎜> <🎜> | <🎜>Group name<🎜> |
<🎜>note<🎜> | <🎜>varchar(128)<🎜> | <🎜> <🎜> | <🎜>Group Description<🎜> |
<🎜>level<🎜> | <🎜>int<🎜> | <🎜> <🎜> | <🎜>Group Level<🎜> |
5) D_group_access table: records the three-dimensional permission information of each GModule, different background user groups and various operation permissions.
Table 3-5 User group permissions table for Module
|
type
|
default
|
<🎜>info<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>id<🎜> | <🎜>int<🎜> | <🎜>auto_increment<🎜> | <🎜>PRI<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>group_id<🎜> | <🎜>int<🎜> | <🎜> <🎜> | <🎜>Group id<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>module_id<🎜> | <🎜>int<🎜> | <🎜> <🎜> | <🎜>Module module ID<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>edit<🎜> | <🎜>int<🎜> | <🎜>1<🎜> | <🎜>Editable<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>view<🎜> | <🎜>int<🎜> | <🎜>1<🎜> | <🎜>Can be viewed<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>delete<🎜> | <🎜>int<🎜> | <🎜>1<🎜> | <🎜>can be deleted<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>export<🎜> | <🎜>int<🎜> | <🎜>1<🎜> | <🎜>Exportable<🎜> |
<🎜>field<🎜> | <🎜>type<🎜> | <🎜>default<🎜> | <🎜>info<🎜> |
<🎜>id<🎜> | <🎜>int<🎜> | <🎜>auto_increment<🎜> | <🎜>PRI<🎜> |
<🎜>user_id<🎜> | <🎜>int<🎜> | <🎜> <🎜> | <🎜>User id<🎜> |
<🎜>ip_addr<🎜> | <🎜>varchar(15)<🎜> | <🎜> <🎜> | <🎜>Client IP<🎜> |
<🎜>module_id<🎜> | <🎜>int<🎜> | <🎜> <🎜> | <🎜>Accessed moduleid<🎜> |
<🎜>module_title<🎜> | <🎜>varchar(16)<🎜> | <🎜> <🎜> | <🎜> <🎜> |
<🎜>task<🎜> | <🎜>varchar(16)<🎜> | <🎜> <🎜> | <🎜>Operation<🎜> |
<🎜>created_at<🎜> | <🎜>timestamp<🎜> | <🎜> <🎜> | <🎜>Exportable<🎜> |
DBuilder needs to support multiple data sources and multiple types of databases. Data source information is stored in the d_database table. Considering that database operations are frequent operations, if the data source information is saved in the database, each database operation will require one more data source query operation, which wastes performance. Then DBuilder should not save the data source information in the database, but in the code file. Data source management information includes data source name (the unique identifier of the data source, DBuilder’s default data source name is core), database type, address, port, database name, user name, password and other information. Because the data source management module does not perform addition, deletion, modification, and query operations on tables, the data source management module is not a GModule module. The code for this module is entirely hand-written.
DBuilder will use the GModule named "Module" as the user interface for generating GModule. This module is called the GModule management module. In other words, the GModule management module itself is a GModule, and the main table of the GModule is the core data. In the database table that stores GModule information in the source, change the name of GModule to "Module". GModule management module contains all code files and database records for creating, updating and deleting GModule. The creation and deletion of GModule requires updating the global GModule routing.
1) GModule routing
The GModule route is defined in an independent code file. It is a string with the GModule name divided by minus signs and all lowercase as the key (for example: the GModule name is OrderItem, then the key value is order-item), with Module The class name of the Controller class is a map dictionary of values, and the GModule routing is global.
2) GModule New & Update
Creating a new GModule will generate a record in the database, generate all module files, and update routes. The update operation only modifies the configuration file. Both new creation and update use the same editing view, which is a graphical configuration interface for GModule Configuration.
3) GModule Delete
GModule deletion will delete all GModule MVC code, delete GModule Configuration code, delete database table records, and update GModule routing.
Core CRUD module is the actual processor of DBuilder to handle CRUD requests. It consists of the following parts:
1) Parameter analysis initialization
Initialize the Model and instantiate a Module's Model object as the initial queryer. Load Module Configuration, set default values for unset values, and aggregate parameters.
2) Form Form
Mainly includes new and update functions. Determine whether it is a new or update operation based on whether the primary key of the GModule main table primaryKey is set. The picture below is the process of the Form module
Figure 3-5 Form execution process
Form is divided into two parts. The first part renders the Form page for the user to fill in. The second part is saved as Form.
When rendering a Form page, you need to consider how to handle Form controls and fields with foreign key relationships. Form controls need to support types including text, text_date, text_datetime, textarea, select, radio, checkbox, file, hidden, address, and custom. Custom controls should inherit the FormControl class, and the rendering of custom controls is completed by the render method of the control. Form rendering needs to determine related fields for auxiliary loading. For example, when editing the post table, the post table has a field called category_id, which represents the column ID of the article and corresponds to the id field of the category table. At this time, you need to use select, radio, and checkbox controls to load category_id to facilitate user input. For example, if you use the select control, category.id should be used as the value of the option, and category.name should be used as the text in the option. This is also done to facilitate user input. This step has something in common with searching in List, so the code can be reused.
Form saving needs to consider the saving of some custom controls. The saving of custom controls is completed by the onSave method of the custom control class. When saving the Form, you also need to consider saving the relationship. By default, the subsidiary tables should be updated in cascade. After the user completes the input and clicks Save, the Form form has the following steps:
Form also needs to open the corresponding pre-processing and post-processing interfaces.
3) List List(Table)
List is a paging Table, which displays paging data according to the field configuration in Module Configuration. Supports list search, sorting, check deletion, export and other functions;
4) View View
View is temporarily based on Form and provides pre-processing and post-processing interfaces, but does not allow editing.
The code is stored in sub-directories according to concepts such as front-end resources, MVC, Configuration, and Library. A description of the main directories is given in the table below:
Table 4-2 Main directory of code
|
Function
|
||||||||||||||||||||||||||||
assets |
This directory stores various front-end resources. Includes bootstrap, as well as custom css and js files.
|
||||||||||||||||||||||||||||
plugins
|
Directory that stores special front-end plug-ins, such as rich text editors, video and audio plug-ins, etc.
|
||||||||||||||||||||||||||||
<🎜>app/controllers/admin<🎜> | <🎜> Directory that stores controllers in MVC. Among them, the core of DBuilder is in the admin directory. <🎜> | ||||||||||||||||||||||||||||
<🎜>app/models<🎜> | <🎜>The directory that stores the models in MVC. Used for database queries. <🎜> | ||||||||||||||||||||||||||||
<🎜>app/views<🎜> | <🎜>The directory that stores views in MVC. The file name is in the format *.blade.php. <🎜> | ||||||||||||||||||||||||||||
<🎜>app/library<🎜> | <🎜> Directory that stores PHP auxiliary classes and PHP libraries. <🎜> | ||||||||||||||||||||||||||||
<🎜>app/config/crud<🎜> | <🎜>The directory where Module Configuration is stored. <🎜> |
<🎜>Configuration Key<🎜> | <🎜>Type<🎜> | <🎜>Default value<🎜> | <🎜>Meaning<🎜> |
<🎜>fields<🎜> | <🎜>array<🎜> | <🎜>array()<🎜> | <🎜>Field list<🎜> |
<🎜>fields.field_name<🎜> | <🎜>array<🎜> | <🎜>array()<🎜> | <🎜>Configuration of field_name field<🎜> |
<🎜>fields.field_name.label<🎜> | <🎜>string<🎜> | <🎜>UP(field_name)<🎜> | <🎜>The content displayed in the header of the list table and the content next to the form control<🎜> |
<🎜>fields.field_name.form<🎜> | <🎜>array<🎜> | <🎜>array()<🎜> | <🎜>Form configuration of field_name field, please refer to <🎜> for details <🎜>fields.field_name.form configuration<🎜> |
<🎜>fields.field_name.list<🎜> | <🎜>array<🎜> | <🎜>array()<🎜> | <🎜>List configuration of field_name field, please refer to <🎜> for details <🎜>fields.field_name.list configuration<🎜> <🎜> <🎜> |
<🎜>fields.field_name. relation<🎜> | <🎜>array<🎜> | <🎜>array()<🎜> | <🎜>Relationship between field_name fields<🎜> |
The form configuration description of each field in Table 4-3 is as shown in the following table:
Table 4-4 fields.field_name.form configuration
|
Value type
|
Default
|
Meaning |
||||||||||||||||||||||||||||||||||||||||||||||||
type |
|
<🎜>text<🎜> | <🎜>Form control type<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>show<🎜> | <🎜>bool<🎜> | <🎜>true<🎜> | <🎜>Whether it appears in the form<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>hidden<🎜> | <🎜>bool<🎜> | <🎜>false<🎜> | <🎜>Whether to hide the space in the form<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>rule<🎜> | <🎜>string<🎜> | <🎜>required<🎜> | <🎜>Validation Rules<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>ajax_validate<🎜> | <🎜>bool<🎜> | <🎜>false<🎜> | <🎜>Whether to verify asynchronously<🎜> | ||||||||||||||||||||||||||||||||||||||||||||||||
<🎜>placeholder<🎜> | <🎜>string<🎜> | <🎜> <🎜> | <🎜>Prompts in controls<🎜> |
<🎜>Configuration Key<🎜> | <🎜>Value type<🎜> | <🎜>Default<🎜> | <🎜>Meaning<🎜> |
<🎜>show<🎜> | <🎜>bool<🎜> | <🎜>true<🎜> | <🎜>Whether it appears in the form<🎜> |
<🎜>sort<🎜> | <🎜>bool<🎜> | <🎜>true<🎜> | <🎜>Whether the field can be sorted, it can be sorted by default<🎜> |
<🎜>search<🎜> | <🎜>bool,array<🎜> | <🎜>array()<🎜> | <🎜>Whether it is searchable and search rules<🎜> |
<🎜> <🎜> | <🎜>string<🎜> | <🎜> <🎜> | <🎜>Prompts in controls<🎜> |
<🎜>Configuration Key<🎜> | <🎜>Value type<🎜> | <🎜>Default<🎜> | <🎜>Meaning<🎜> |
<🎜>table<🎜> | <🎜>string<🎜> | <🎜> <🎜> | <🎜>Association table<🎜> |
<🎜>foreign_key<🎜> | <🎜>string<🎜> | <🎜>id<🎜> | <🎜>Corresponds to the fields in the related table<🎜> |
<🎜>show<🎜> | <🎜>string<🎜> | <🎜> <🎜> | <🎜>A field in the associated table. When escaping is required, this field will be used to display instead of the field_nae field<🎜> |
<🎜>as<🎜> | <🎜>string<🎜> | <🎜>table_show<🎜> | <🎜>Which field should be used to represent the value from the escaped query? This is mainly to prevent duplicate fields in the main table and related tables<🎜> |
The following is the Configuration file of a GModule named post
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 ConfigurationThe data source management module completes the configuration of the app/config/datasource.php file based on the web interface. Contains data source list page, data source creation and editing page.
The core controller code that implements data source management is placed in the DataSourceController.php file.
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 IlluminateSupportFacadesConfig; 13 use IlluminateSupportFacadesRedirect; 14 use SiteHelpers; 15 use IlluminateSupportFacadesResponse; 16 use IlluminateSupportFacadesInput; 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 IlluminateHttpJsonResponse 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 IlluminateHttpJsonResponse 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