2021SC@SDUSC
此次接着分析文件 src/controller/admin/model.js
该文件中的方法为模型操作,在整个项目中有着举足轻重的地位。
一、editextAction()
此方法用于编辑独立模型。
如果请求加载了数据,获取post的数据,并设置数据的更新时间。如果获取的数据 post.attribute_list 为数组,那么将它作为字符串返回,数组中的元素由分隔符“,”分隔。
变量res用于确定数据是否成功更新到数据库中。若更新成功,那么将模型添加到钩子里并更新钩子。之后生成或更新配置文件,更新缓存,告知系统更新模型成功。
如果没有请求加载数据,获取id,并依照id在数据库中查找单条数据,赋值给data。若data的attribute_list不为空,那么我们将 attribute_list 依照“,”分割成字符串数组。
实例化模型 attribute ,查找 model_id = data.id 、字段限制为id,name,title,is_show 的多条数据,并将得到的数据赋值给 fields 。
判断 data 是否继承了其他模型。若继承了其他模型,则获取相应数据赋值给 extend_field ,并将 extend_field 与 fields 合并赋值给 allfields ;否则将 fields 赋值给 allfields 。
使用 JSON.parse() 方法将 data.field_sort 转换为JavaScript对象,并赋值给 field_sort。
最后,将变量 fields,extend_fields,orderbgy,data 中的值分配给模型字段 ‘fields’, ‘extend_fields’, ‘allfields’, ‘info’ ,方法结束并返回。
到这里可以发现,这里的编辑独立模型方法和前一篇中的编辑模型方法逻辑基本一致,只是多了与钩子相关的一些方法。关于钩子的具体分析,可以在同组同学的博客中找到,在此不再赘述。
async editextAction() {
if (this.isPost) {
const post = this.post();
post.ismod = 1;
post.update_time = new Date().valueOf();
if (think.isArray(post.attribute_list)) {
post.attribute_list = post.attribute_list.join(',');
}
console.log(post);
if (!think.isEmpty(post.hooks) && think.isArray(post.hooks)) {
post.hooks = post.hooks.join(',');
}
const res = await this.db.update(post);
if (res) {
if (!think.isEmpty(post.hooks)) {
for (const h of post.hooks.split(',')) {
const hooks = await this.model('hooks').where({name: h}).find();
let extarr = hooks.ext ? hooks.ext.split(',') : [];
extarr.push(post.name);
extarr = think._.uniq(extarr);
await this.model('hooks').where({name: h}).update({ext: extarr.join(',')});
}
}
const configs = await this.model('model').fieldReverse('id').find(post.id);
const moddir = `${think.APP_PATH}/controller/mod`;
const modpath = `${moddir}/${configs.name}`;
fs.writeFileSync(`${modpath}/config.js`, `module.exports = ${JSON.stringify(configs)}`);
await update_cache('model');
return this.success({name: '更新模型成功!', url: '/admin/model/ext'});
}
} else {
const id = this.get('id');
let allfields;
if (think.isEmpty(id)) {
this.fail('参数不能为空!');
}
const data = await this.db.find(id);
data.attribute_list = think.isEmpty(data.attribute_list) ? '' : data.attribute_list.split(',');
const fields = await this.model('attribute').where({model_id: data.id}).field('id,name,title,is_show').select();
if (data.extend != 0) {
var extend_fields = await this.model('attribute').where({model_id: data.extend}).field('id,name,title,is_show').select();
allfields = fields.concat(extend_fields);
} else {
allfields = fields;
}
for (const field of allfields) {
if (!think.isEmpty(data.attribute_list) && !in_array(field.id, data.attribute_list)) {
field.is_show = 0;
}
var obj = {};
if (allfields) {
for (const v of allfields) {
obj[v.id] = v;
}
} else {
for (const v of fields) {
obj[v.id] = v;
}
}
const field_sort = JSON.parse(data.field_sort);
if (!think.isEmpty(field_sort)) {
for (const group in field_sort) {
field_sort[group].forEach((v, k) => {
if (obj[v]) {
obj[v].group = group;
obj[v].sort = k;
}
});
}
}
const order = think._.values(obj);
const orderbgy = think._.orderBy(order, ['group', 'sort'], ['asc', 'asc']);
if (!think.isEmpty(data.hooks)) {
data.hooks = data.hooks.split(',');
}
const hooks = await this.model('hooks').select();
this.assign('hooks', hooks);
this.assign({'fields': fields, 'extend_fields': extend_fields, 'allfields': orderbgy, 'info': data});
this.tactive = 'ext';
this.active = 'admin/model/ext';
this.meta_title = '编辑模型';
return this.display();
}
}
二、unextAction()
此方法用于卸载独立模型。
首先获取 id,并依照 id 在数据库中查找单条数据,赋值给 m 。依据 m ,我们可以通过 think.isEmpty(m.table) 来判断数据库的数据库表是否为空,若不为空则删除。随后我们通过数据库查找数据并进行删除:删除该模型的分类、清除搜索索引、清除搜索配置、清除话题数据。
最后删除整个模型并更新缓存,告知系统 “ 卸载成功,移动到未安装!”
async unextAction() {
const id = this.get('id');
const m = await this.model('model').find(id);
console.log(m);
if (!think.isEmpty(m.table)) {
await this.deltable(m.table.split(','), m.name);
}
const cats = await this.model('category').where({model: m.id}).getField('id');
if (!think.isEmpty(cats)) {
await this.model('category').where({id: ['IN', cats]}).delete();
console.log('删除分类');
await this.model('category_priv').where({catid: ['IN', cats]}).delete();
console.log('清除分类权限');
}
await this.model('search').where({m_id: m.id}).delete();
console.log('清除 搜索索引');
await this.model('search_model').where({mod: m.id}).delete();
if (m.key_show === 1) {
await this.model('keyword_data').where({mod_id: m.id}).delete();
console.log('清除 话题数据');
}
await this.model('model').where({id: m.id}).delete();
await update_cache('model');
return this.success({name: '卸载成功,移动到未安装!'});
}
三、delextAction()
此方法用于删除插件。
首先根据 mod 判断该插件是否允许被删除,若 mod 与 ‘demo’ 等价则不允许删除。若允许删除,获取相应目录下的数据 data ,以进行后续操作。
由 data 获取数据库中的表,若数据库不为空,则删除数据库内的表和数据库。删除完成后,给主进程发送重启的指令,告知系统“删除成功!”。
删除表的方法为 deltable() 方法,此方法为自定义方法。
async delextAction() {
const mod = this.get('mod');
if (mod === 'demo') return this.fail('不允许删除');
const modpath = `${think.APP_PATH}/controller/mod/${mod}`;
const data = think.app.controllers[`mod/${mod}/config`];
const tables = data.table;
if (!think.isEmpty(tables)) {
await this.deltable(tables.split(','), mod);
}
await think.rmdir(modpath).then(() => {
console.log('删除完成');
});
process.send('think-cluster-reload-workers');
return this.success({name: '删除成功!'});
}