【20211222】CmsWing代码分析 - src/controller/extend/controller.js(三)

2021SC@SDUSC

目录

src/controller/extend/controller.js

modModel(modelName = '', extName = '', config = this.config('model.mysql'), prefix = '') {
    let p = this.ctx.controller.split('/');
    if (this.ctx.controller === 'cmswing/route' || this.ctx.controller === 'cmswing/modadminbase') {
      p = `mod/${this.mod.name}/index`.split('/');
    }
    extName = think.isEmpty(extName) ? p[1] : extName;
    return think.modModel(modelName, extName, config, prefix);
  },

模型。参数是:模型名称,扩展名称,配置,前缀。

config处官方文档给出的使用方法如下:think.config(name, value, m)
name {String} 配置名
value {Mixed} 配置值
m {String} 模块名,多模块项目下使用
读取或者设置配置,该功能由think-config模块实现。在 context、controller、logic上可以直接通过this.config方法来操作配置。

// 获取配置
const value1 = think.config('name');
// 指定模块获取配置,多模块项目下有效
const value2 = think.config('name', undefined, 'admin');

// 设置配置
think.config('name', 'value');
// 指定模块设置配置值
think.config('name', 'value', 'admin');

于是在这里读取的是model.mysql,数据库相关。

ctx.controller是路由解析后的控制器名,split方法用于把一个字符串分割成字符串数组。因此变量p就是控制器名(如果以斜杠/分隔);如果控制器名是cmswing/route或者cmswing/modadminbase,则是这个字符串mod/${this.mod.name}/index分割成数组。

如果扩展名是空的,就设置成变量p的[1]位置。

modService(name = '', ser = '', ...args) {
    let p = this.ctx.controller.split('/');
    if (this.ctx.controller === 'cmswing/route' || this.ctx.controller === 'cmswing/modadminbase') {
      p = `mod/${this.mod.name}/index`.split('/');
    }
    ser = think.isEmpty(ser) ? p[1] : ser;
    return think.modService(name, ser, ...args);
  },

整个和上一段的逻辑几乎一致,不再重复分析。

async hook(hooks, ...args) {
    try {
      const h = await this.model('cmswing/hooks').hookscache(hooks);
      if (!think.isEmpty(h.ext)) {
        const ext = h.ext.split(',');
        const hookarr = [];
        for (const c of ext) {
          // 查询插件状态
          const status = await this.model('cmswing/ext').extcache(c, 'status');
          if (Number(status) === 1) {
            const ep = `ext/${c}/hooks`;
            const Cls = this.controller(ep);
            if (Number(h.type) === 1) {
              hookarr.push(await Cls[hooks](...args));
            } else {
              return Cls[hooks](...args);
            }
          } else {
            const models = await this.model('cmswing/model').get_model(null, null, {name: c});
            // console.log(models);
            if (!think.isEmpty(models)) {
              const ep = `mod/${c}/hooks`;
              const Cls = this.controller(ep);
              if (Number(h.type) === 1) {
                hookarr.push(await Cls[hooks](...args));
              } else {
                return Cls[hooks](...args);
              }
            }
          }
        }

        const type = think._.last(args);
        if (think.isObject(type) && !think.isEmpty(type.$hook_key) && !think.isEmpty(type.$hook_type)) {
          const cachehook = await think.cache(`hooks_${hooks}${type.$hook_type}${this.cookie('thinkjs')}`);
          const hookobj = think.isEmpty(cachehook) ? {} : cachehook;
          if (!think.isEmpty(hookarr)) {
            hookobj[type.$hook_key] = hookarr.join('');
          }
          await think.cache(`hooks_${hooks}${type.$hook_type}${this.cookie('thinkjs')}`, hookobj);
          return this.assign(`HOOKS@${hooks}@${type.$hook_type}`, await think.cache(`hooks_${hooks}${type.$hook_type}${this.cookie('thinkjs')}`));
        }
        if (think.isObject(type) && !think.isEmpty(type.$hook_type)) {
          return this.assign(`HOOK@${hooks}@${type.$hook_type}`, hookarr.join(''));
        }
        if (think.isObject(type) && !think.isEmpty(type.$hook_key)) {
          const hookobj = think.isEmpty(await think.cache(`hooks_${hooks}${this.cookie('thinkjs')}`)) ? {} : await think.cache(`hooks_${hooks}${this.cookie('thinkjs')}`);
          if (!think.isEmpty(hookarr)) {
            hookobj[type.$hook_key] = hookarr.join('');
          }
          await think.cache(`hooks_${hooks}${this.cookie('thinkjs')}`, hookobj);
          return this.assign(`HOOKS@${hooks}`, await think.cache(`hooks_${hooks}${this.cookie('thinkjs')}`));
        }
        this.assign(`HOOK@${hooks}`, hookarr.join(''));
      }
    } catch (e) {
      think.logger.error(e);
    }
  },

非常长的一段和hook相关的代码,整体可以拆成这样的结构。首先最外层是一个try-catch结构捕获异常:

async hook(hooks, ...args) {
    try {^} catch (e) {
      think.logger.error(e);
    }
  },

在其中又是一层if判断:

const h = await this.model('cmswing/hooks').hookscache(hooks);
if (!think.isEmpty(h.ext)) {^}

h表示hook的缓存,非空才能够进入内层的逻辑:

const ext = h.ext.split(',');
const hookarr = [];
for (const c of ext) {
	// 查询插件状态
	const status = await this.model('cmswing/ext').extcache(c, 'status');
	if (Number(status) === 1) {
		const ep = `ext/${c}/hooks`;
		const Cls = this.controller(ep);
		if (Number(h.type) === 1) {
			hookarr.push(await Cls[hooks](...args));
		} else {
			return Cls[hooks](...args);
		}
	} else {
		const models = await this.model('cmswing/model').get_model(null, null, {name: c});
		// console.log(models);
		if (!think.isEmpty(models)) {
			const ep = `mod/${c}/hooks`;
			const Cls = this.controller(ep);
			if (Number(h.type) === 1) {
				hookarr.push(await Cls[hooks](...args));
			} else {
				return Cls[hooks](...args);
			}
		}
	}
}

内层包括了一系列判断条件。对每个hook进行状态判断,并且针对空的情况做出不同的处理方式。

上一篇:react hooks自定义组件居然能这样做


下一篇:关于hooks,你该知道的