diff --git a/.jshintrc b/.jshintrc index e8735827..a9930ed7 100644 --- a/.jshintrc +++ b/.jshintrc @@ -155,6 +155,7 @@ "BELONGS_TO": true, "HAS_MANY": true, "MANY_TO_MANY": true, - "isDate": true + "isDate": true, + "getThinkRequirePath": true } } \ No newline at end of file diff --git a/coverage.html b/coverage.html index 0073b33e..596283a1 100644 --- a/coverage.html +++ b/coverage.html @@ -351,4 +351,4 @@ code .init { color: #2F6FAD } code .string { color: #5890AD } code .keyword { color: #8A6343 } code .number { color: #2F6FAD } -

Coverage

94%
252
237
15

/Users/welefen/Develop/git/thinkjs/lib/Common/common.js

93%
239
224
15
LineHitsSource
11var fs = require('fs');
21var path = require('path');
31var util = require('util');
41var crypto = require('crypto');
51var net = require('net');
6
7/**
8 * 由于非常依赖promise,所以将promise设置为全局变量
9 * @type {[type]}
10 */
111global.Promise = require('es6-promise').Promise;
12
13/**
14 * 动态创建一个类
15 * 提供了继承、扩展、调用父级别方法等方法
16 * @return {[type]} [description]
17 */
181global.Class = function (prop, superCls) {
194 'use strict';
204 var cls = function () {
214 function T(args) {
224 for(var name in cls.__prop){
2310 var val = cls.__prop[name];
2410 this[name] = isObject(val) ? extend({}, val) : val;
25 }
26 //自动执行init方法
274 if(isFunction(this.init)){
28 //获取init返回值,如果返回一个promise,可以让后续执行在then之后
294 this.__initReturn = this.init.apply(this, args);
30 }
314 return this;
32 }
334 T.prototype = cls.prototype;
344 T.constructor = cls;
354 return new T(arguments);
36 };
37 //类的属性,不放在原型上,实例化的时候调用
384 cls.__prop = {};
394 cls.extend = function(prop){
403 if (isFunction(prop)) {
411 prop = prop();
42 }
433 if (isObject(prop)) {
443 for(var name in prop){
4516 var val = prop[name];
4616 if (isFunction(val)) {
4710 this.prototype[name] = val;
48 }else{
496 cls.__prop[name] = isObject(val) ? extend({}, val) : val;
50 }
51 }
52 }
533 return this;
54 };
554 cls.inherits = function(superCls){
563 util.inherits(this, superCls);
57 //将父级的属性复制到当前类上
583 extend(cls.__prop, superCls.__prop);
593 return this;
60 };
614 if (superCls === true && isFunction(prop)) {
621 superCls = prop;
631 prop = undefined;
64 }
654 if (isFunction(superCls)) {
663 cls.inherits(superCls);
67 }
68 //调用父级方法
694 cls.prototype.super = cls.prototype.super_ = function(name, data){
70 //如果当前类没有这个方法,则直接返回。
71 //用于在a方法调用父级的b方法
726 if (!this[name]) {
731 return;
74 }
755 var super_ = this.constructor.super_;
76 //如果父级没有这个方法,那么直接返回
775 if (!isFunction(super_.prototype[name])) {
781 return;
79 }
80 //如果参数不是数组,自动转为数组
814 if (!isArray(data)) {
824 data = [data];
83 }
844 while(1){
855 if (this[name] === super_.prototype[name] && super_.super_) {
861 super_ = super_.super_;
87 }else{
884 break;
89 }
90 }
914 var method = super_.prototype[name];
924 delete super_.prototype[name];
934 var ret = method.apply(this, data);
944 super_.prototype[name] = method;
954 return ret;
96 };
974 if (prop) {
983 cls.extend(prop);
99 }
1004 return cls;
101};
102/**
103 * extend, from jquery,具有深度复制功能
104 * @return {[type]} [description]
105 */
1061global.extend = function(){
10723 'use strict';
10823 var args = [].slice.call(arguments);
10923 var deep = true;
11023 var target = args.shift();
11123 if (isBoolean(target)) {
1128 deep = target;
1138 target = args.shift();
114 }
11523 target = target || {};
11623 var length = args.length;
11723 var options, name, src, copy, copyAsArray, clone;
11823 for(var i = 0; i < length; i++){
11923 options = args[i] || {};
12023 if (isFunction(options)) {
1211 options = options();
122 }
12323 for(name in options){
12434 src = target[name];
12534 copy = options[name];
12634 if (src === copy) {
1272 continue;
128 }
12932 if (deep && copy && (isObject(copy) || (copyAsArray = isArray(copy) ))) {
1306 if (copyAsArray) {
1311 copyAsArray = false;
1321 clone = src && isArray(src) ? src : [];
133 }else{
1345 clone = src && isObject(src) ? src : {};
135 }
1366 target[name] = extend(deep, clone, copy);
13726 }else if (copy !== undefined) {
13826 target[name] = copy;
139 }
140 }
141 }
14223 return target;
143};
144
145
146//Object上toString方法
1471var toString = Object.prototype.toString;
148
149/**
150 * 是否是boolean
151 * @param {[type]} obj
152 * @return {Boolean}
153 */
1541global.isBoolean = function(obj){
15534 'use strict';
15634 return toString.call(obj) === '[object Boolean]';
157};
158/**
159 * 是否是数字
160 * @param {[type]} obj [description]
161 * @return {Boolean} [description]
162 */
1631global.isNumber = function(obj){
16418 'use strict';
16518 return toString.call(obj) === '[object Number]';
166};
167/**
168 * 是否是个对象
169 * @param {[type]} obj [description]
170 * @return {Boolean} [description]
171 */
1721global.isObject = function(obj){
17366 'use strict';
17466 return toString.call(obj) === '[object Object]';
175};
176/**
177 * 是否是字符串
178 * @param {[type]} obj [description]
179 * @return {Boolean} [description]
180 */
1811global.isString = function(obj){
18212 'use strict';
18312 return toString.call(obj) === '[object String]';
184};
185/**
186 * 是否是个function
187 * @param {[type]} obj [description]
188 * @return {Boolean} [description]
189 */
1901global.isFunction = function(obj){
19165 'use strict';
19265 return typeof obj === 'function';
193};
194/**
195 * 是否是日期
196 * @return {Boolean} [description]
197 */
1981global.isDate = function(obj){
1992 'use strict';
2002 return util.isDate(obj);
201};
202/**
203 * 是否是正则
204 * @param {[type]} reg [description]
205 * @return {Boolean} [description]
206 */
2071global.isRegexp = function(obj){
2082 'use strict';
2092 return util.isRegExp(obj);
210};
211/**
212 * 是否是个错误
213 * @param {[type]} obj [description]
214 * @return {Boolean} [description]
215 */
2161global.isError = function(obj){
2172 'use strict';
2182 return util.isError(obj);
219};
220/**
221 * 判断对象是否为空
222 * @param {[type]} obj
223 * @return {Boolean}
224 */
2251global.isEmpty = function(obj){
22612 'use strict';
22712 if (isObject(obj)) {
2282 var key;
2292 for(key in obj){
2301 return false;
231 }
2321 return true;
23310 }else if (isArray(obj)) {
2341 return obj.length === 0;
2359 }else if (isString(obj)) {
2362 return obj.length === 0;
2377 }else if (isNumber(obj)) {
2382 return obj === 0;
2395 }else if (obj === null || obj === undefined) {
2402 return true;
2413 }else if (isBoolean(obj)) {
2422 return !obj;
243 }
2441 return false;
245};
246/**
247 * 是否是个标量
248 * @param {[type]} obj [description]
249 * @return {Boolean} [description]
250 */
2511global.isScalar = function(obj){
2521 'use strict';
2531 return isBoolean(obj) || isNumber(obj) || isString(obj);
254};
255/**
256 * 是否是个数组
257 * @type {Boolean}
258 */
2591global.isArray = Array.isArray;
260/**
261 * 是否是IP
262 * @type {Boolean}
263 */
2641global.isIP = net.isIP;
2651global.isIP4 = net.isIP4;
2661global.isIP6 = net.isIP6;
267/**
268 * 是否是个文件
269 * @param {[type]} p [description]
270 * @return {Boolean} [description]
271 */
2721global.isFile = function(p){
2734 'use strict';
2744 if (!fs.existsSync(p)) {
2752 return false;
276 }
2772 var stats = fs.statSync(p);
2782 return stats.isFile();
279};
280/**
281 * 是否是个目录
282 * @param {[type]} p [description]
283 * @return {Boolean} [description]
284 */
2851global.isDir = function(p){
2863 'use strict';
2873 if (!fs.existsSync(p)) {
2881 return false;
289 }
2902 var stats = fs.statSync(p);
2912 return stats.isDirectory();
292};
293/**
294 * 是否是buffer
295 * @type {Boolean}
296 */
2971global.isBuffer = Buffer.isBuffer;
298/**
299 * 是否是个数字的字符串
300 * @param {[type]} obj [description]
301 * @return {Boolean} [description]
302 */
3031var numberReg = /^((\d*\.?\d*(?:e[+-]?\d*(?:\d?\.?|\.?\d?)\d*)?)|(0[0-7]+)|(0x[0-9a-f]+))$/i;
3041global.isNumberString = function(obj){
3053 'use strict';
3063 return numberReg.test(obj);
307};
308/**
309 * 判断是否是个promise
310 * @param {[type]} obj [description]
311 * @return {Boolean} [description]
312 */
3131global.isPromise = function(obj){
31412 'use strict';
31512 return !!(obj && typeof obj.then === 'function');
316};
317
318/**
319 * 判断一个文件或者目录是否可写
320 * @param {[type]} p [description]
321 * @return {Boolean} [description]
322 */
3231global.isWritable = function(p){
3243 'use strict';
3253 if (!fs.existsSync(p)) {
3261 return false;
327 }
3282 var stats = fs.statSync(p);
3292 var mode = stats.mode;
3302 var uid = process.getuid ? process.getuid() : 0;
3312 var gid = process.getgid ? process.getgid() : 0;
3322 var owner = uid === stats.uid;
3332 var group = gid === stats.gid;
3342 return !!(owner && (mode & parseInt('00200', 8)) ||
335 group && (mode & parseInt('00020', 8)) ||
336 (mode & parseInt('00002', 8)));
337};
338
339/**
340 * 递归创建目录,同步模式
341 * @param {[type]} p [description]
342 * @param {[type]} mode [description]
343 * @return {[type]} [description]
344 */
3451global.mkdir = function(p, mode){
3461 'use strict';
3471 mode = mode || '0777';
3481 if (fs.existsSync(p)) {
3490 chmod(p, mode);
3500 return true;
351 }
3521 var pp = path.dirname(p);
3531 if (fs.existsSync(pp)) {
3541 fs.mkdirSync(p, mode);
355 }else{
3560 mkdir(pp, mode);
3570 mkdir(p, mode);
358 }
3591 return true;
360};
361/**
362 * 修改目录或者文件权限
363 * @param {[type]} p [description]
364 * @param {[type]} mode [description]
365 * @return {[type]} [description]
366 */
3671global.chmod = function(p, mode){
3680 'use strict';
3690 mode = mode || '0777';
3700 if (!fs.existsSync(p)) {
3710 return true;
372 }
3730 return fs.chmodSync(p, mode);
374};
375/**
376 * 获取文件内容
377 * @param {[type]} file [description]
378 * @return {[type]} [description]
379 */
3801global.getFileContent = function(file, encoding){
3810 'use strict';
3820 if (!fs.existsSync(file)) {
3830 return '';
384 }
3850 return fs.readFileSync(file, {
386 encoding: encoding || 'utf8'
387 });
388};
389/**
390 * 设置文件内容
391 * @param {[type]} file [description]
392 * @param {[type]} data [description]
393 * @return {[type]} [description]
394 */
3951global.setFileContent = function(file, data){
3960 'use strict';
3970 return fs.writeFileSync(file, data);
398};
399/**
400 * 大写首字符
401 * @param {[type]} name [description]
402 * @return {[type]} [description]
403 */
4041global.ucfirst = function(name){
4056 'use strict';
4066 name = (name || '') + '';
4076 return name.substr(0,1).toUpperCase() + name.substr(1).toLowerCase();
408};
409/**
410 * 获取字符串的md5
411 * @param {[type]} str [description]
412 * @return {[type]} [description]
413 */
4141global.md5 = function(str){
4152 'use strict';
4162 var instance = crypto.createHash('md5');
4172 instance.update(str + '');
4182 return instance.digest('hex');
419};
420/**
421 * 生成一个promise,如果传入的参数是promise则直接返回
422 * @param {[type]} obj [description]
423 * @return {[type]} [description]
424 */
4251global.getPromise = function(obj, reject){
4267 'use strict';
4277 if (isPromise(obj)) {
4281 return obj;
429 }
4306 if (reject) {
4312 return Promise.reject(obj);
432 }
4334 return Promise.resolve(obj);
434};
435/**
436 * 生成一个defer对象
437 * @return {[type]} [description]
438 */
4391global.getDefer = function(){
4401 'use strict';
4411 var deferred = {};
4421 deferred.promise = new Promise(function(resolve, reject){
4431 deferred.resolve = resolve;
4441 deferred.reject = reject;
445 });
4461 return deferred;
447};
448/**
449 * 快速生成一个object
450 * @param {[type]} key [description]
451 * @param {[type]} value [description]
452 * @return {[type]} [description]
453 */
4541global.getObject = function(key, value){
4555 'use strict';
4565 var obj = {};
4575 if (!isArray(key)) {
4582 obj[key] = value;
4592 return obj;
460 }
4613 key.forEach(function(item, i){
4625 obj[item] = value[i];
463 });
4643 return obj;
465};
466/**
467 * 将数组变成对象
468 * @param {[type]} arr [description]
469 * @param {[type]} key [description]
470 * @param {[type]} valueKeys [description]
471 * @return {[type]} [description]
472 */
4731global.arrToObj = function(arr, key, valueKey){
4744 'use strict';
4754 var result = {};
4764 var arrResult = [];
4774 arr.forEach(function(item){
4788 var keyValue = item[key];
4798 if (valueKey === null) {
4804 arrResult.push(keyValue);
4814 }else if (valueKey) {
4822 result[keyValue] = item[valueKey];
483 }else{
4842 result[keyValue] = item;
485 }
486 })
4874 return valueKey === null ? arrResult : result;
488}

/Users/welefen/Develop/git/thinkjs/lib/Common/extend.js

100%
13
13
0
LineHitsSource
1//该文件内容为原生对象的扩展
2
3/**
4 * 获取对象的值
5 * @param {[type]} obj [description]
6 * @return {[type]} [description]
7 */
81Object.values = function(obj){
92 'use strict';
102 var values = [];
112 for(var key in obj){
121 if (obj.hasOwnProperty(key)) {
131 values.push(obj[key])
14 }
15 }
162 return values;
17};
18/**
19 * 数组求和
20 * @return {[type]} [description]
21 */
221Array.prototype.sum = function(){
237 'use strict';
247 var count = 0;
257 this.forEach(function(item){
2623 count += parseFloat(item) || 0;
27 });
287 return count;
29};
30
\ No newline at end of file +

Coverage

27%
3110
853
2257

/Users/welefen/Develop/git/thinkjs/lib/Common/common.js

94%
239
227
12
LineHitsSource
11var fs = require('fs');
21var path = require('path');
31var util = require('util');
41var crypto = require('crypto');
51var net = require('net');
6
7/**
8 * 由于非常依赖promise,所以将promise设置为全局变量
9 * @type {[type]}
10 */
111global.Promise = require('es6-promise').Promise;
12
13/**
14 * 动态创建一个类
15 * 提供了继承、扩展、调用父级别方法等方法
16 * @return {[type]} [description]
17 */
181global.Class = function (prop, superCls) {
1935 'use strict';
2035 var cls = function () {
2115 function T(args) {
2215 for(var name in cls.__prop){
2323 var val = cls.__prop[name];
2423 this[name] = isObject(val) ? extend({}, val) : val;
25 }
26 //自动执行init方法
2715 if(isFunction(this.init)){
28 //获取init返回值,如果返回一个promise,可以让后续执行在then之后
2915 this.__initReturn = this.init.apply(this, args);
30 }
3115 return this;
32 }
3315 T.prototype = cls.prototype;
3415 T.constructor = cls;
3515 return new T(arguments);
36 };
37 //类的属性,不放在原型上,实例化的时候调用
3835 cls.__prop = {};
3935 cls.extend = function(prop){
4036 if (isFunction(prop)) {
4134 prop = prop();
42 }
4336 if (isObject(prop)) {
4434 for(var name in prop){
45353 var val = prop[name];
46353 if (isFunction(val)) {
47308 this.prototype[name] = val;
48 }else{
4945 cls.__prop[name] = isObject(val) ? extend({}, val) : val;
50 }
51 }
52 }
5336 return this;
54 };
5535 cls.inherits = function(superCls){
5622 util.inherits(this, superCls);
57 //将父级的属性复制到当前类上
5822 extend(cls.__prop, superCls.__prop);
5922 return this;
60 };
6135 if (superCls === true && isFunction(prop)) {
621 superCls = prop;
631 prop = undefined;
64 }
6535 if (isFunction(superCls)) {
6622 cls.inherits(superCls);
67 }
68 //调用父级方法
6935 cls.prototype.super = cls.prototype.super_ = function(name, data){
70 //如果当前类没有这个方法,则直接返回。
71 //用于在a方法调用父级的b方法
726 if (!this[name]) {
731 return;
74 }
755 var super_ = this.constructor.super_;
76 //如果父级没有这个方法,那么直接返回
775 if (!isFunction(super_.prototype[name])) {
781 return;
79 }
80 //如果参数不是数组,自动转为数组
814 if (!isArray(data)) {
824 data = [data];
83 }
844 while(1){
855 if (this[name] === super_.prototype[name] && super_.super_) {
861 super_ = super_.super_;
87 }else{
884 break;
89 }
90 }
914 var method = super_.prototype[name];
924 delete super_.prototype[name];
934 var ret = method.apply(this, data);
944 super_.prototype[name] = method;
954 return ret;
96 };
9735 if (prop) {
9834 cls.extend(prop);
99 }
10035 return cls;
101};
102/**
103 * extend, from jquery,具有深度复制功能
104 * @return {[type]} [description]
105 */
1061global.extend = function(){
107104 'use strict';
108104 var args = [].slice.call(arguments);
109104 var deep = true;
110104 var target = args.shift();
111104 if (isBoolean(target)) {
11240 deep = target;
11340 target = args.shift();
114 }
115104 target = target || {};
116104 var length = args.length;
117104 var options, name, src, copy, copyAsArray, clone;
118104 for(var i = 0; i < length; i++){
119104 options = args[i] || {};
120104 if (isFunction(options)) {
1211 options = options();
122 }
123104 for(name in options){
124240 src = target[name];
125240 copy = options[name];
126240 if (src === copy) {
12726 continue;
128 }
129214 if (deep && copy && (isObject(copy) || (copyAsArray = isArray(copy) ))) {
13038 if (copyAsArray) {
13112 copyAsArray = false;
13212 clone = src && isArray(src) ? src : [];
133 }else{
13426 clone = src && isObject(src) ? src : {};
135 }
13638 target[name] = extend(deep, clone, copy);
137176 }else if (copy !== undefined) {
138176 target[name] = copy;
139 }
140 }
141 }
142104 return target;
143};
144
145
146//Object上toString方法
1471var toString = Object.prototype.toString;
148
149/**
150 * 是否是boolean
151 * @param {[type]} obj
152 * @return {Boolean}
153 */
1541global.isBoolean = function(obj){
155115 'use strict';
156115 return toString.call(obj) === '[object Boolean]';
157};
158/**
159 * 是否是数字
160 * @param {[type]} obj [description]
161 * @return {Boolean} [description]
162 */
1631global.isNumber = function(obj){
16418 'use strict';
16518 return toString.call(obj) === '[object Number]';
166};
167/**
168 * 是否是个对象
169 * @param {[type]} obj [description]
170 * @return {Boolean} [description]
171 */
1721global.isObject = function(obj){
173288 'use strict';
174288 return toString.call(obj) === '[object Object]';
175};
176/**
177 * 是否是字符串
178 * @param {[type]} obj [description]
179 * @return {Boolean} [description]
180 */
1811global.isString = function(obj){
182201 'use strict';
183201 return toString.call(obj) === '[object String]';
184};
185/**
186 * 是否是个function
187 * @param {[type]} obj [description]
188 * @return {Boolean} [description]
189 */
1901global.isFunction = function(obj){
191670 'use strict';
192670 return typeof obj === 'function';
193};
194/**
195 * 是否是日期
196 * @return {Boolean} [description]
197 */
1981global.isDate = function(obj){
1992 'use strict';
2002 return util.isDate(obj);
201};
202/**
203 * 是否是正则
204 * @param {[type]} reg [description]
205 * @return {Boolean} [description]
206 */
2071global.isRegexp = function(obj){
2082 'use strict';
2092 return util.isRegExp(obj);
210};
211/**
212 * 是否是个错误
213 * @param {[type]} obj [description]
214 * @return {Boolean} [description]
215 */
2161global.isError = function(obj){
2172 'use strict';
2182 return util.isError(obj);
219};
220/**
221 * 判断对象是否为空
222 * @param {[type]} obj
223 * @return {Boolean}
224 */
2251global.isEmpty = function(obj){
22612 'use strict';
22712 if (isObject(obj)) {
2282 var key;
2292 for(key in obj){
2301 return false;
231 }
2321 return true;
23310 }else if (isArray(obj)) {
2341 return obj.length === 0;
2359 }else if (isString(obj)) {
2362 return obj.length === 0;
2377 }else if (isNumber(obj)) {
2382 return obj === 0;
2395 }else if (obj === null || obj === undefined) {
2402 return true;
2413 }else if (isBoolean(obj)) {
2422 return !obj;
243 }
2441 return false;
245};
246/**
247 * 是否是个标量
248 * @param {[type]} obj [description]
249 * @return {Boolean} [description]
250 */
2511global.isScalar = function(obj){
2521 'use strict';
2531 return isBoolean(obj) || isNumber(obj) || isString(obj);
254};
255/**
256 * 是否是个数组
257 * @type {Boolean}
258 */
2591global.isArray = Array.isArray;
260/**
261 * 是否是IP
262 * @type {Boolean}
263 */
2641global.isIP = net.isIP;
2651global.isIP4 = net.isIP4;
2661global.isIP6 = net.isIP6;
267/**
268 * 是否是个文件
269 * @param {[type]} p [description]
270 * @return {Boolean} [description]
271 */
2721global.isFile = function(p){
27349 'use strict';
27449 if (!fs.existsSync(p)) {
27524 return false;
276 }
27725 var stats = fs.statSync(p);
27825 return stats.isFile();
279};
280/**
281 * 是否是个目录
282 * @param {[type]} p [description]
283 * @return {Boolean} [description]
284 */
2851global.isDir = function(p){
2863 'use strict';
2873 if (!fs.existsSync(p)) {
2881 return false;
289 }
2902 var stats = fs.statSync(p);
2912 return stats.isDirectory();
292};
293/**
294 * 是否是buffer
295 * @type {Boolean}
296 */
2971global.isBuffer = Buffer.isBuffer;
298/**
299 * 是否是个数字的字符串
300 * @param {[type]} obj [description]
301 * @return {Boolean} [description]
302 */
3031var numberReg = /^((\d*\.?\d*(?:e[+-]?\d*(?:\d?\.?|\.?\d?)\d*)?)|(0[0-7]+)|(0x[0-9a-f]+))$/i;
3041global.isNumberString = function(obj){
3053 'use strict';
3063 return numberReg.test(obj);
307};
308/**
309 * 判断是否是个promise
310 * @param {[type]} obj [description]
311 * @return {Boolean} [description]
312 */
3131global.isPromise = function(obj){
31433 'use strict';
31533 return !!(obj && typeof obj.then === 'function');
316};
317
318/**
319 * 判断一个文件或者目录是否可写
320 * @param {[type]} p [description]
321 * @return {Boolean} [description]
322 */
3231global.isWritable = function(p){
3243 'use strict';
3253 if (!fs.existsSync(p)) {
3261 return false;
327 }
3282 var stats = fs.statSync(p);
3292 var mode = stats.mode;
3302 var uid = process.getuid ? process.getuid() : 0;
3312 var gid = process.getgid ? process.getgid() : 0;
3322 var owner = uid === stats.uid;
3332 var group = gid === stats.gid;
3342 return !!(owner && (mode & parseInt('00200', 8)) ||
335 group && (mode & parseInt('00020', 8)) ||
336 (mode & parseInt('00002', 8)));
337};
338
339/**
340 * 递归创建目录,同步模式
341 * @param {[type]} p [description]
342 * @param {[type]} mode [description]
343 * @return {[type]} [description]
344 */
3451global.mkdir = function(p, mode){
3461 'use strict';
3471 mode = mode || '0777';
3481 if (fs.existsSync(p)) {
3490 chmod(p, mode);
3500 return true;
351 }
3521 var pp = path.dirname(p);
3531 if (fs.existsSync(pp)) {
3541 fs.mkdirSync(p, mode);
355 }else{
3560 mkdir(pp, mode);
3570 mkdir(p, mode);
358 }
3591 return true;
360};
361/**
362 * 修改目录或者文件权限
363 * @param {[type]} p [description]
364 * @param {[type]} mode [description]
365 * @return {[type]} [description]
366 */
3671global.chmod = function(p, mode){
3680 'use strict';
3690 mode = mode || '0777';
3700 if (!fs.existsSync(p)) {
3710 return true;
372 }
3730 return fs.chmodSync(p, mode);
374};
375/**
376 * 获取文件内容
377 * @param {[type]} file [description]
378 * @return {[type]} [description]
379 */
3801global.getFileContent = function(file, encoding){
3811 'use strict';
3821 if (!fs.existsSync(file)) {
3830 return '';
384 }
3851 return fs.readFileSync(file, {
386 encoding: encoding || 'utf8'
387 });
388};
389/**
390 * 设置文件内容
391 * @param {[type]} file [description]
392 * @param {[type]} data [description]
393 * @return {[type]} [description]
394 */
3951global.setFileContent = function(file, data){
3960 'use strict';
3970 return fs.writeFileSync(file, data);
398};
399/**
400 * 大写首字符
401 * @param {[type]} name [description]
402 * @return {[type]} [description]
403 */
4041global.ucfirst = function(name){
40511 'use strict';
40611 name = (name || '') + '';
40711 return name.substr(0,1).toUpperCase() + name.substr(1).toLowerCase();
408};
409/**
410 * 获取字符串的md5
411 * @param {[type]} str [description]
412 * @return {[type]} [description]
413 */
4141global.md5 = function(str){
4152 'use strict';
4162 var instance = crypto.createHash('md5');
4172 instance.update(str + '');
4182 return instance.digest('hex');
419};
420/**
421 * 生成一个promise,如果传入的参数是promise则直接返回
422 * @param {[type]} obj [description]
423 * @return {[type]} [description]
424 */
4251global.getPromise = function(obj, reject){
42628 'use strict';
42728 if (isPromise(obj)) {
4287 return obj;
429 }
43021 if (reject) {
4312 return Promise.reject(obj);
432 }
43319 return Promise.resolve(obj);
434};
435/**
436 * 生成一个defer对象
437 * @return {[type]} [description]
438 */
4391global.getDefer = function(){
4402 'use strict';
4412 var deferred = {};
4422 deferred.promise = new Promise(function(resolve, reject){
4432 deferred.resolve = resolve;
4442 deferred.reject = reject;
445 });
4462 return deferred;
447};
448/**
449 * 快速生成一个object
450 * @param {[type]} key [description]
451 * @param {[type]} value [description]
452 * @return {[type]} [description]
453 */
4541global.getObject = function(key, value){
4555 'use strict';
4565 var obj = {};
4575 if (!isArray(key)) {
4582 obj[key] = value;
4592 return obj;
460 }
4613 key.forEach(function(item, i){
4625 obj[item] = value[i];
463 });
4643 return obj;
465};
466/**
467 * 将数组变成对象
468 * @param {[type]} arr [description]
469 * @param {[type]} key [description]
470 * @param {[type]} valueKeys [description]
471 * @return {[type]} [description]
472 */
4731global.arrToObj = function(arr, key, valueKey){
4744 'use strict';
4754 var result = {};
4764 var arrResult = [];
4774 arr.forEach(function(item){
4788 var keyValue = item[key];
4798 if (valueKey === null) {
4804 arrResult.push(keyValue);
4814 }else if (valueKey) {
4822 result[keyValue] = item[valueKey];
483 }else{
4842 result[keyValue] = item;
485 }
486 })
4874 return valueKey === null ? arrResult : result;
488}

/Users/welefen/Develop/git/thinkjs/lib/Common/extend.js

100%
13
13
0
LineHitsSource
1//该文件内容为原生对象的扩展
2
3/**
4 * 获取对象的值
5 * @param {[type]} obj [description]
6 * @return {[type]} [description]
7 */
81Object.values = function(obj){
94 'use strict';
104 var values = [];
114 for(var key in obj){
121 if (obj.hasOwnProperty(key)) {
131 values.push(obj[key])
14 }
15 }
164 return values;
17};
18/**
19 * 数组求和
20 * @return {[type]} [description]
21 */
221Array.prototype.sum = function(){
237 'use strict';
247 var count = 0;
257 this.forEach(function(item){
2623 count += parseFloat(item) || 0;
27 });
287 return count;
29};
30

/Users/welefen/Develop/git/thinkjs/lib/Common/function.js

62%
161
100
61
LineHitsSource
11var fs = require('fs');
21var path = require('path');
3
4
51var _alias = {};
61var _autoload_callbacks = [];
7/**
8 * thinkRequire获取到的路径
9 * @param {[type]} name [description]
10 * @return {[type]} [description]
11 */
121function getThinkRequirePath(name){
1372 'use strict';
1472 if (_alias[name]) {
1553 return _alias[name];
16 }
1719 var result = '';
1819 _autoload_callbacks.some(function(callback){
1919 result = callback && callback(name);
2019 if (result) {
2118 return true;
22 }
23 });
2419 return result;
25}
26/**
27 * 自定义的require, 加入别名功能
28 * @type {[type]}
29 */
301global.thinkRequire = function(name){
3172 'use strict';
32 //如果不是字符串则直接返回
3372 if (!isString(name)) {
341 return name;
35 }
3671 var path = name;
3771 if (path[0] !== '/') {
3871 path = getThinkRequirePath(name);
39 }
4071 if (path) {
4170 var obj = require(path);
4270 if (isFunction(obj)) {
43 //修正子类继承的方法获取到正确的文件名
4464 obj.prototype.__filename = path;
45 }
4670 return obj;
47 }
481 return require(name);
49};
50/**
51 * 注册require
52 * @param {Function} callback [description]
53 * @return {[type]} [description]
54 */
551global.registerAutoload = function(callback){
561 'use strict';
571 _autoload_callbacks.push(callback);
58};
59/**
60 * 别名
61 * @return {[type]} [description]
62 */
631global.aliasImport = function(alias, classFile){
6419 'use strict';
6519 if (isString(alias)) {
6618 _alias[alias] = classFile;
67 }else{
681 _alias = extend(_alias, alias);
69 }
70};
71
72//常用类的基类
731['Cache', 'Behavior', 'Controller', 'Session', 'Model', 'Db'].forEach(function(item){
746 'use strict';
756 global[item] = function(super_, obj){
7617 if (isString(super_)) {
771 return Class(obj, thinkRequire(super_));
78 }
7916 return Class(super_, thinkRequire(item));
80 };
81});
82
83
84/**
85 * 调用一个指定的行为
86 * @param {[type]} name [description]
87 */
881global.B = function(name, http, data){
896 'use strict';
906 if (typeof name === 'function') {
910 return name(http, data);
92 }
936 return thinkRequire(name + 'Behavior')(http).run(data);
94};
95
96/**
97 * 处理标签扩展
98 * @return {[type]} [description]
99 */
1001global.tag = function(name, http, data){
10112 'use strict';
10212 var sys_tags = (C('sys_tag.' + name) || []).slice();
10312 var tags = (C('tag.' + name) || []).slice();
104 //tag处理的数据
10512 http.tag_data = data;
10612 if (tags.length) {
1070 if (typeof tags[0] === 'boolean') {
1080 var flag = tags.shift();
109 //为true时自定义tag覆盖sys tag, false是自定义tag添加到sys tag之前
1100 if (!flag) {
1110 tags = tags.concat(sys_tags);
112 }
113 }else{
114 //默认是自定义tag放在sys tag之后
1150 tags = sys_tags.concat(tags);
116 }
117 }else{
11812 tags = sys_tags;
119 }
12012 function runBehavior(){
12112 var behavior = tags.shift();
12212 if (!behavior) {
1236 return http.tag_data;
124 }
1256 var result = B(behavior, http, http.tag_data);
1266 return getPromise(result).then(function(data){
1276 if (data !== undefined) {
1286 http.tag_data = data;
129 }
1306 return runBehavior();
131 })
132 }
13312 return getPromise(tags.length ? runBehavior() : http.tag_data);
134};
135/**
136 * 配置读取和写入
137 */
1381var _config = {};
1391global.C = function(name, value){
14075 'use strict';
141 //获取所有的配置
14275 if (arguments.length === 0) {
1431 return _config;
144 }
145 //清除所有的配置
14674 if (name === null) {
1471 _config = {};
148 }
14974 if (isString(name)) {
15070 name = name.toLowerCase();
15170 if (name.indexOf('.') === -1) {
15246 if (value === undefined) {
15345 return _config[name];
154 }
1551 _config[name] = value;
1561 return;
157 }
15824 name = name.split('.');
15924 if (value === undefined) {
16024 value = _config[name[0]] || {};
16124 return value[name[1]];
162 }
1630 if (!_config[name[0]]) {
1640 _config[name[0]] = {};
165 }
1660 _config[name[0]][name[1]] = value;
167 }else{
1684 _config = extend(_config, name);
169 }
170};
171/**
172 * 实例化Controller类,可以调用一个具体的Action
173 * A('Home/Index'), A('Admin/Index/test')
174 * @param {[type]} name [description]
175 */
1761global.A = function(name, http, data){
1771 'use strict';
1781 if (name.indexOf('/') > -1) {
1791 name = name.split('/');
1800 }else if (name.indexOf(':') > -1) {
1810 name = name.split(':');
182 }else{
1830 name = [name];
184 }
1851 var action;
1861 if (name.length === 3) {
1870 action = name.pop();
188 }
1891 var controller = name.pop() || http.controller;
1901 var group = name.pop() || http.group;
1911 var gm = ucfirst(group) + '/' + ucfirst(controller);
1921 var path = getThinkRequirePath(gm + 'Controller');
1931 if (path) {
1941 var instance = require(path)(http);
1951 if (action) {
1960 action += C('action_suffix');
1970 if (arguments.length === 2) {
1980 data = [];
1990 }else if (!isArray(data)) {
2000 data = [data];
201 }
2020 return instance[action].apply(instance, data);
203 }
2041 return instance;
205 }
2060 return null;
207};
208
209/**
210 * 快速文件读取和写入
211 * 默认写入到App/Runtime/Data目录下
212 */
2131global.F = function(name, value, rootPath){
2140 'use strict';
2150 if (rootPath === undefined) {
2160 rootPath = DATA_PATH;
217 }
2180 var filePath = rootPath + '/' + name + '.json';
2190 if (value !== undefined) {
2200 mkdir(path.dirname(filePath));
2210 fs.writeFile(filePath, JSON.stringify(value), function(){
2220 chmod(filePath);
223 });
2240 return;
225 }
2260 if (isFile(filePath)) {
2270 var content = getFileContent(filePath);
2280 if (content) {
2290 return JSON.parse(content);
230 }
231 }
2320 return false;
233};
234/**
235 * 实例化模型
236 */
2371global.D = function(name, tablePrefix, config){
2380 'use strict';
2390 if (name === undefined) {
2400 return thinkRequire('Model')(name, tablePrefix, config);
241 }
2420 name = name.split(':');
2430 var path = getThinkRequirePath(name[0] + 'Model');
2440 if (path) {
2450 return thinkRequire(name[0] + 'Model')(name[1], tablePrefix, config);
246 }else{
2470 return thinkRequire(name[1] === 'AdvModel' ? 'AdvModel' : 'Model')(name[0], tablePrefix, config);
248 }
249};
250/**
251 * 实例化模型基类
252 * @param {[type]} name [description]
253 * @param {[type]} tablePrefix [description]
254 * @param {[type]} config [description]
255 */
2561global.M = function(name, tablePrefix, config){
2570 'use strict';
2580 if (name === undefined) {
2590 return thinkRequire('Model')(name, tablePrefix, config);
260 }
2610 name = name.split(':');
2620 var model = name[1] === 'AdvModel' ? 'AdvModel' : 'Model';
2630 return thinkRequire(model)(name[0], tablePrefix, config)
264}
265/**
266 * 缓存的设置和读取
267 * 获取返回的是一个promise
268 */
2691global.S = function(name, value, options){
2700 'use strict';
2710 if (options && !isObject(options)) {
2720 options = {timeout: options};
273 }
2740 options = options || {};
2750 var type = options.type === undefined ? C('cache_type') : options.type;
2760 var instance = thinkRequire(ucfirst(type.toLowerCase()) + 'Cache')(options);
277 //获取缓存
2780 if (value === undefined) {
2790 return instance.get(name);
280 }
281 //移除缓存
2820 if (value === null) {
2830 return instance.rm(name);
284 }
2850 return instance.set(name, value, options.timeout);
286};
287/**
288 * 语言
289 * @param {[type]} name [description]
290 */
2911global.L = function(name){
2920 'use strict';
2930 return name;
294};

/Users/welefen/Develop/git/thinkjs/lib/Conf/alias.js

100%
1
1
0
LineHitsSource
1/**
2 * 模块别名,模块名到具体的路径,模块名不能有重复
3 * 使用thinkRequire加载模块时有效
4 * @type {Object}
5 */
61module.exports = {
7 Controller: THINK_LIB_PATH + '/Core/Controller.js',
8 App: THINK_LIB_PATH + '/Core/App.js',
9 Behavior: THINK_LIB_PATH + '/Util/Behavior.js',
10 Cache: THINK_LIB_PATH + '/Util/Cache.js',
11 Db: THINK_LIB_PATH + '/Core/Db.js',
12 Dispatcher: THINK_LIB_PATH + '/Core/Dispatcher.js',
13 Filter: THINK_LIB_PATH + '/Util/Filter.js',
14 Http: THINK_LIB_PATH + '/Core/Http.js',
15 //Log: THINK_LIB_PATH + '/Util/Log.js',
16 Model: THINK_LIB_PATH + '/Core/Model.js',
17 Session: THINK_LIB_PATH + '/Util/Session.js',
18 Think: THINK_LIB_PATH + '/Core/Think.js',
19 Valid: THINK_LIB_PATH + '/Util/Valid.js',
20 View: THINK_LIB_PATH + '/Core/View.js',
21 Cookie: THINK_LIB_PATH + '/Util/Cookie.js',
22 WebSocket: THINK_LIB_PATH + '/Util/WebSocket.js'
23};

/Users/welefen/Develop/git/thinkjs/lib/Conf/config.js

100%
1
1
0
LineHitsSource
1 /**
2 * 框架默认配置
3 * 可以在App/Conf/config.js里修改下面的配置值
4 * @type {Object}
5 */
61module.exports = {
7 port: 8360, //监听端口
8 use_proxy: false, //是否使用代理访问,如:nginx。开启后不能通过ip+端口直接访问
9 encoding: 'utf8', //输出数据的编码
10 url_pathname_prefix: '', //不解析的pathname前缀
11 url_pathname_suffix: '.html', //不解析的pathname后缀,这样利于seo
12 app_tag_on: true, //是否支持标签功能
13 url_resource_on: true, //是否监听静态资源类请求
14 url_resource_reg: /^(resource\/|static\/|favicon\.ico)/, //判断是否是静态资源的正则
15 url_route_on: true, //是否开启自定义路由功能
16
17 post_json_content_type: ['application/json'], //post数据为json时的content-type
18 post_data_async: false, //POST提交的数据异步获取,默认为同步获取
19 post_max_file_size: 1024 * 1024 * 1024, //上传文件大小限制,默认1G
20 post_max_fields: 1000, //最大表单数
21 post_max_fields_size: 2 * 1024, //单个表单最大值
22
23 app_group_list: ['Home', 'Admin'], //分组列表
24 default_group: 'Home', //默认分组
25 default_controller: 'Index', //默认模块
26 default_action: 'index', //默认Action
27 call_controller: 'Home:Index:_404', //controller不存在时执行方法,此配置表示调用Home分组下IndexController的_404Action方法
28 call_method: '__call', //当找不到方法时调用什么方法,这个方法存在时才有效
29 before_action_name: '__before', //调用一个action前调用的方法,会将action名传递进去
30 after_action_name: '__after', //调用一个action之后调用的方法,会将action名传递进去
31 url_params_bind: true, //方法参数绑定,将URL参数值绑定到action的参数上
32 action_suffix: 'Action', //action后缀
33 url_callback_name: 'callback', //jsonp格式的callback名字
34 json_content_type: 'application/json', //发送json时的content-type
35 auto_send_content_type: true, //是否自动发送Content-Type,默认值为`tpl_content_type`配置值
36 log_process_pid: true, //记录进程的id,方便其他脚本处理。
37 use_cluster: false, //是否使用cluster,默认不使用,0:为cpu的数量,可以自定义值
38 autoload_path: {}, //autoload查找的path,用于thinkRequire加载自定义库的时候查找
39 create_server_fn: '', //自定义create server全局函数名,可以在Common/common.js里实现
40
41 load_ext_config: [], //加载额外的配置文件 CONF_PATH
42 load_ext_file: [], //加载额外的文件 COMMON_PATH
43
44 use_websocket: false, //是否使用websocket
45 websocket_allow_origin: '', //允许从那里发送过来的websocket,可以是字符串、数组、回调函数,为空表示不检测
46 websocket_sub_protocal: '', //websocket子协议,可以是个字符串也可以是回调函数
47 websocket_message_handle: undefined, //websocket消息处理函数
48
49 error_tpl_path: THINK_PATH + '/View/error.html', //错误页模版
50 error_no_key: 'errno', //错误number的key
51 error_no_default_value: 1000, //错误号默认值
52 error_msg_key: 'errmsg', //错误消息的key
53
54 cookie_domain: '', //cookie有效域名
55 cookie_path: '/', //cookie路径
56 cookie_timeout: 0, //cookie失效时间,0为浏览器关闭,单位:秒
57
58 session_name: 'thinkjs', //session对应的cookie名称
59 session_type: 'File', //session存储类型, 空为内存,还可以为File
60 session_path: '', //File类型下文件存储位置,默认为系统的tmp目录
61 session_options: {}, //session对应的cookie选项
62 session_sign: '', //session对应的cookie使用签名
63 session_timeout: 24 * 3600, //session失效时间,单位:秒
64
65 db_type: 'mysql', // 数据库类型
66 db_host: 'localhost', // 服务器地址
67 db_port: '', // 端口
68 db_name: '', // 数据库名
69 db_user: 'root', // 用户名
70 db_pwd: '', // 密码
71 db_prefix: 'think_', // 数据库表前缀
72 db_fieldtype_check: false, // 是否进行字段类型检查
73 db_fields_cache: true, // 启用字段缓存
74 db_charset: 'utf8', // 数据库编码默认采用utf8
75 db_nums_per_page: 20, //默认每页显示的条数
76 db_like_fields: [], //自动进行模糊查询,|连接,如: ['title', 'content']
77 db_cache_on: true, //是否启用查询缓存,如果关闭那么cache方法则无效
78 db_cache_type: '', //缓存类型,默认为内存缓存
79 db_cache_path: CACHE_PATH + '/db', //缓存路径,File类型下有效
80 db_cache_timeout: 3600, //缓存时间,默认为1个小时
81
82 tpl_content_type: 'text/html', //模版输出类型
83 tpl_file_suffix: '.html', //模版文件名后缀
84 tpl_file_depr: '_', //controller和action之间的分隔符
85 tpl_engine_type: 'ejs', //模版引擎名称
86 tpl_engine_config: {},
87
88 cache_type: 'File', //数据缓存类型
89 cache_timeout: 6 * 3600, //数据缓存有效期,单位: 秒
90 cache_path: CACHE_PATH, //缓存路径设置 (File缓存方式有效)
91 cache_file_suffix: '.json', //File缓存方式下文件后缀名
92 cache_gc_hour: [4], //缓存清除的时间点,数据为小时
93
94 html_cache_on: false, //HTML静态缓存
95 html_cache_timeout: 3600, //缓存时间,单位为秒
96 html_cache_rules: {}, //缓存规则
97 html_cache_path: CACHE_PATH + '/html',
98 html_cache_file_callback: undefined, //生成缓存文件的回调函数
99 html_cache_file_suffix: '.html', //缓存文件后缀名
100
101 memcache_host: '127.0.0.1', //memcache host
102 memcache_port: 11211, //memecache端口
103};

/Users/welefen/Develop/git/thinkjs/lib/Conf/mode.js

100%
1
1
0
LineHitsSource
1/**
2 * 不同模式下的配置文件
3 * 由于每个模式下的配置可能都比较少,所以放在一个文件里
4 * @type {Object}
5 */
61module.exports = {
7 cli: {
8 use_cluster: false,
9 html_cache_on: false,
10 log_process_pid: false,
11 clear_require_cache: false
12 },
13 cli_debug: {
14 clear_require_cache: false
15 }
16};

/Users/welefen/Develop/git/thinkjs/lib/Conf/tag.js

100%
1
1
0
LineHitsSource
1/**
2 * 系统标签配置
3 * 可以在App/Conf/tag.js里进行修改
4 * @type {Object}
5 */
61module.exports = {
7 //应用初始化
8 app_init: [],
9 //pathinfo解析
10 path_info: [],
11 //静态资源请求检测
12 resource_check: ['CheckResource'],
13 //路由检测
14 route_check: ['CheckRoute'],
15 //应用开始
16 app_begin: ['ReadHtmlCache'],
17 //action执行初始化
18 action_init: [],
19 //模版解析初始化
20 view_init: [],
21 //定位模版文件
22 view_template: ['LocationTemplate'],
23 //模版解析
24 view_parse: ['ParseTemplate'],
25 //模版内容过滤
26 view_filter: [],
27 //模版解析结束
28 view_end: ['WriteHtmlCache'],
29 //action结束
30 action_end: [],
31 //应用结束
32 app_end: []
33};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/CheckResourceBehavior.js

48%
25
12
13
LineHitsSource
11var fs = require('fs');
21var mime = require('mime');
3/**
4 * 静态资源请求
5 * @return {[type]} [description]
6 */
71module.exports = Behavior(function(){
81 'use strict';
91 return {
10 options: {
11 'url_resource_on': false
12 },
13 run: function(){
141 if (!RESOURCE_PATH || !this.options.url_resource_on || !this.http.pathname) {
150 return false;
16 }
171 var pathname = this.http.pathname;
181 if (pathname.indexOf('/') === 0) {
191 pathname = pathname.substr(1);
20 }
211 var reg = C('url_resource_reg');
22 //通过正则判断是否是静态资源请求
231 if (!reg.test(pathname)) {
241 return false;
25 }
26
270 var file = RESOURCE_PATH + '/' + pathname;
280 var res = this.http.res;
290 if (fs.existsSync(file)) {
300 var contentType = mime.lookup(file);
310 var fileStream = fs.createReadStream(file);
320 res.setHeader('Content-Type', contentType + '; charset=' + C('encoding'));
330 fileStream.pipe(res);
340 fileStream.on('end', function(){
350 res.end();
36 });
37 }else{
380 res.statusCode = 404;
390 res.end();
40 }
41 //返回一个pendding promise, 不让后续执行
420 return getDefer().promise;
43 }
44 };
45});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/CheckRouteBehavior.js

11%
90
10
80
LineHitsSource
1/**
2 * 检测路由行为
3 * 通过自定义路由识别到对应的URL上
4 * @return {[type]} [description]
5 */
61var url = require('url');
71var Dispatcher = thinkRequire('Dispatcher');
8
91module.exports = Behavior(function(){
101 'use strict';
111 return {
12 options: {
13 'url_route_on': false, //是否开启自定义URL路由
14 'url_route_rules': [] //自定义URL路由规则
15 },
16 run: function(){
171 if (!this.options.url_route_on) {
180 return false;
19 }
201 var routes = this.options.url_route_rules;
211 var length = routes.length;
221 if (length === 0) {
231 return false;
24 }
250 var pathname = this.http.pathname;
260 var match;
270 for(var i = 0; i < length; i++){
280 var route = routes[i];
290 var rule = route[0];
30 //正则路由
310 if (isRegexp(rule)) {
320 match = pathname.match(rule);
330 if (match) {
340 var result = this.parseRegExp(match, route[1], pathname);
350 if (result) {
360 return result;
37 }
38 }
39 }else{
40 //字符串路由
410 match = this.checkUrlMatch(pathname, rule);
420 if (match) {
430 return this.parseRule(rule, route[1], pathname);
44 }
45 }
46 }
470 return false;
48 },
49 /**
50 * 解析字符串路由
51 * @param {[type]} rule [description]
52 * @param {[type]} route [description]
53 * @param {[type]} pathname [description]
54 * @return {[type]} [description]
55 */
56 parseRule: function(rule, route, pathname){
570 route = this.getRoute(route);
580 if (!route) {
590 return false;
60 }
610 pathname = pathname.split('/').filter(function(item){
620 return item.trim();
63 });
640 rule = rule.split('/').filter(function(item){
650 return item.trim();
66 });
670 var matches = {};
680 rule.forEach(function(item){
690 var pathitem = pathname.shift();
700 if (item.indexOf(':') === 0) {
710 matches[item] = pathitem;
72 }
73 });
74 //将剩余的pathname分割为querystring
750 if (pathname.length) {
760 for(var i = 0,length = Math.ceil(pathname.length)/2; i < length; i++){
770 this.http.get[pathname[i * 2]] = pathname[i * 2 + 1] || '';
78 }
79 }
800 var values = Object.values(matches);
810 route = route.replace(/:(\d+)/g, function(a, b){
820 return values[b - 1] || '';
83 });
840 this.parseUrl(route);
850 return true;
86 },
87 /**
88 * 检测URL是否匹配
89 * @param {[type]} pathname [description]
90 * @param {[type]} rule [description]
91 * @return {[type]} [description]
92 */
93 checkUrlMatch: function(pathname, rule){
940 pathname = pathname.split('/').filter(function(item){
950 return item.trim();
96 });
970 rule = rule.split('/').filter(function(item){
980 return item.trim();
99 });
1000 return rule.every(function(item, i){
1010 if (item.indexOf(':') === 0) {
1020 if (item.indexOf('\\') > -1) {
1030 var type = item.substr(-1);
1040 if (type === 'd' && !isNumberString(pathname[i])) {
1050 return false;
106 }
107 }
108 }else{
1090 var pitem = pathname[i] || '';
1100 if (pitem.toLowerCase() !== item.toLowerCase()) {
1110 return false;
112 }
113 }
1140 return true;
115 });
116 },
117 /**
118 * 解析转化后的url
119 * @param {[type]} urlInfo [description]
120 * @return {[type]} [description]
121 */
122 parseUrl: function(urlInfo){
1230 urlInfo = url.parse(urlInfo, true);
1240 if (urlInfo.query) {
1250 for(var key in urlInfo.query){
1260 if (urlInfo.query[key] || !(key in this.http.get)) {
1270 this.http.get[key] = urlInfo.query[key];
128 }
129 }
130 }
1310 var pathname = urlInfo.pathname || '';
132 // 过滤调用pathname最后有/的情况
1330 pathname = pathname.split('/').filter(function(item){
1340 return item.trim();
135 });
1360 this.http.action = Dispatcher.getAction(pathname.pop());
1370 this.http.controller = Dispatcher.getController(pathname.pop());
1380 this.http.group = Dispatcher.getGroup(pathname.pop());
139 },
140 /**
141 * 获取route
142 * @param {[type]} route [description]
143 * @return {[type]} [description]
144 */
145 getRoute: function(route){
1460 if (isObject(route)) {
147 //对应的请求类型
1480 for(var method in route){
149 //由于请求类型没有包含关系,这里可以直接用indexOf判断
1500 if (method.toUpperCase().indexOf(this.http.method) > -1) {
1510 return route[method];
152 }
153 }
1540 return;
155 }
1560 return route;
157 },
158 /**
159 * 正则匹配路由
160 * @param {[type]} matches [description]
161 * @param {[type]} route [description]
162 * @param {[type]} pathname [description]
163 * @return {[type]} [description]
164 */
165 parseRegExp: function(matches, route, pathname){
1660 route = this.getRoute(route);
1670 if (!route) {
1680 return false;
169 }
1700 route = route.replace(/:(\d+)/g, function(a, b){
1710 return matches[b] || '';
172 });
1730 pathname = pathname.replace(matches[0], '');
1740 pathname = pathname.split('/').filter(function(item){
1750 return item;
176 });
177 //将剩余的pathname分割为querystring
1780 if (pathname.length) {
1790 for(var i = 0,length = Math.ceil(pathname.length)/2; i < length; i++){
1800 this.http.get[pathname[i * 2]] = pathname[i * 2 + 1] || '';
181 }
182 }
1830 this.parseUrl(route);
1840 return true;
185 }
186 };
187});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/DenyIpBehavior.js

20%
15
3
12
LineHitsSource
1/**
2 * 阻止ip来源访问
3 * @return {[type]} [description]
4 */
51module.exports = Behavior(function(){
61 'use strict';
71 return {
8 options: {
9 deny_ip: [] //阻止的ip列表
10 },
11 run: function(){
120 if (this.options.deny_ip.length === 0) {
130 return true;
14 }
150 var clientIps = this.http.ip().split('.');
160 var flag = this.options.deny_ip.some(function(item){
170 return item.split('.').every(function(num, i){
180 if (num === '*' || num === clientIps[i]) {
190 return true;
20 }
21 });
22 });
23 //如果在阻止的ip在列表里,则返回一个pendding promise,让后面的代码不执行
240 if (flag) {
250 this.http.res.statusCode = 403;
260 this.http.res.end();
270 return getDefer().promise;
28 }
290 return true;
30 }
31 };
32});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/LocationTemplateBehavior.js

47%
21
10
11
LineHitsSource
1/**
2 * 定位模版的行为
3 * @return {[type]} [description]
4 */
5
61module.exports = Behavior(function(){
71 'use strict';
81 return {
9 run: function(templateFile){
101 if (!isFile(templateFile)) {
111 return this.parseTemplateFile(templateFile);
12 }
13 },
14 /**
15 * 解析模版文件
16 * @param {[type]} templateFile [description]
17 * @return {[type]} [description]
18 */
19 parseTemplateFile: function(templateFile){
201 templateFile = templateFile || '';
211 if (!templateFile) {
221 templateFile = [
23 VIEW_PATH, '/', this.http.group, '/',
24 this.http.controller.toLowerCase(),
25 C('tpl_file_depr'),
26 this.http.action.toLowerCase(),
27 C('tpl_file_suffix')
28 ].join('');
290 }else if(templateFile.indexOf('/') > -1){
30 //自动追加VIEW_PATH前缀
310 if (templateFile.indexOf('/') !== 0) {
320 templateFile = VIEW_PATH + '/' + templateFile;
33 }
340 }else if(templateFile.indexOf(C('tpl_file_suffix')) === -1){
350 var path = templateFile.split(':');
360 var action = path.pop();
370 var controller = path.pop() || this.http.controller.toLowerCase();
380 var group = ucfirst(path.pop()) || this.http.group;
390 templateFile = [
40 VIEW_PATH, '/', group, '/',
41 controller,
42 C('tpl_file_depr'),
43 action,
44 C('tpl_file_suffix')
45 ].join('');
46 }
471 if (!isFile(templateFile)) {
480 console.log(templateFile + ' is not exist', this.http);
490 return false;
50 }
511 return templateFile;
52 }
53 };
54});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/ParseTemplateBehavior.js

90%
10
9
1
LineHitsSource
1/**
2 * 调用对应的模版引擎解析模版
3 * @return {[type]} [description]
4 */
51module.exports = Behavior(function(){
61 'use strict';
71 return {
8 run: function(data){
91 var file = data.content || data.file;
10 //将模版文件路径写入到http对象上,供writehtmlcache里使用
111 this.http.tpl_file = file;
121 var engine = C('tpl_engine_type');
13 //不使用模版引擎,直接返回文件内容
141 if (!engine) {
150 return getFileContent(file);
16 }
171 var engineClass = ucfirst(engine) + 'Template';
181 return thinkRequire(engineClass).fetch(file, data.var);
19 }
20 };
21});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/ReadHtmlCacheBehavior.js

10%
64
7
57
LineHitsSource
1//获取模版文件
21var getViewFile = thinkRequire('WriteHtmlCacheBehavior').getViewFile;
31var fs = require('fs');
4/**
5 * 读取HTML缓存
6 * @return {[type]} [description]
7 */
81module.exports = Behavior(function(){
91 'use strict';
101 return {
11 options:{
12 'html_cache_on': false, //是否开启缓存
13 'html_cache_timeout': 3600, //缓存时间
14 'html_cache_rules': {}, //缓存规则
15 'html_cache_path': '',
16 'html_cache_file_callback': undefined, //生成缓存文件的回调函数
17 'html_cache_file_suffix': '.html', //缓存文件扩展名
18 },
19 run: function(){
201 if (!this.options.html_cache_on || isEmpty(this.options.html_cache_rules)) {
211 return false;
22 }
230 var cacheTime = this.getCacheTime();
240 if (cacheTime === false) {
250 return false;
26 }
270 if (this.checkCacheTime(cacheTime)) {
280 this.responseCacheContent();
29 //return a pending promise
300 return getDefer().promise;
31 }
320 return false;
33 },
34 /**
35 * 返回缓存内容
36 * @return {[type]} [description]
37 */
38 responseCacheContent: function(){
390 var http = this.http;
400 var fileStream = fs.createReadStream(this.options.html_cache_path + '/' + http.html_filename);
410 http.setHeader('Content-Type', 'text/html');
420 http.sendTime('Exec-Time');
430 http.sendCookie();
440 fileStream.pipe(http.res);
450 fileStream.on('end', function(){
460 http.end();
47 });
48 },
49 /**
50 * 获取缓存时间
51 * @return {[type]} [description]
52 */
53 getCacheTime: function(){
54 /**
55 * rules数据格式
56 * {
57 * 'index:index': ['index_home', 1800, html_cache_callback]
58 * }
59 * @type {[type]}
60 */
610 var rules = this.options.html_cache_rules;
620 var group = this.http.group.toLowerCase();
630 var controller = this.http.controller.toLowerCase();
640 var action = this.http.action.toLowerCase();
650 var list = [
66 group + ':' + controller + ':' + action,
67 controller + ':' + action,
68 action,
69 '*'
70 ];
710 var html = [];
720 list.some(function(item){
730 if (item in rules) {
740 html = rules[item];
750 return true;
76 }
77 });
780 if (isEmpty(html)) {
790 return false;
80 }
810 if (!isArray(html)) {
820 html = [html];
83 }
840 var rule = html[0];
85 //将cookie变量传递进去
860 var cookiePars = {};
870 for(var name in this.http.cookie){
880 cookiePars['cookie.' + name] = this.http.cookie[name];
89 }
900 var pars = extend({}, this.http.get, cookiePars, {
91 ':group': group,
92 ':controller': controller,
93 ':action': action
94 });
950 rule = rule.replace(/\{([\w\:]+)\}/g, function(a, name){
960 return pars[name] || '';
97 });
980 var callback = html[2] || C('html_cache_file_callback') || this.getCacheFilename;
990 var filename = callback(rule, this.http) + this.options.html_cache_file_suffix;
100 //静态缓存文件名
1010 this.http.html_filename = filename;
1020 var cacheTime = html[1] || this.options.html_cache_timeout;
1030 return cacheTime;
104 },
105 /**
106 *
107 * @param {[type]} key [description]
108 * @return {[type]} [description]
109 */
110 getCacheFilename: function(key){
1110 var value = md5(key);
1120 return value.substr(0, 1) + '/' + value;
113 },
114 /**
115 * [checkCacheTime description]
116 * @return {[type]} [description]
117 */
118 checkCacheTime: function(cacheTime){
1190 var cacheFile = this.options.html_cache_path + '/' + this.http.html_filename;
1200 if (!isFile(cacheFile)) {
1210 return false;
122 }
1230 var cacheFileMtime = fs.statSync(cacheFile).mtime.getTime();
1240 var tplFile = getViewFile(this.http);
1250 if (tplFile) {
1260 if (!isFile(tplFile)) {
1270 return false;
128 }
1290 var tplFileMtime = fs.statSync(tplFile).mtime.getTime();
130 //模版文件有更新
1310 if (tplFileMtime > cacheFileMtime) {
1320 return false;
133 }
134 }
1350 if (Date.now() > (cacheFileMtime + cacheTime * 1000)) {
1360 return false;
137 }
1380 return true;
139 }
140 };
141});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/WriteHtmlCacheBehavior.js

45%
20
9
11
LineHitsSource
1/**
2 * 模版文件列表
3 * @type {Object}
4 */
51var path = require('path');
61var fs = require('fs');
7
81var tplFiles = {};
9/**
10 * 写入html缓存
11 * @return {[type]} [description]
12 */
131module.exports = Behavior(function(){
141 'use strict';
151 return {
16 options: {
17 'html_cache_on': false, //是否开启缓存
18 'html_cache_path': ''
19 },
20 run: function(content){
211 if (!this.options.html_cache_on || !this.http.html_filename) {
221 return content;
23 }
240 this.recordViewFile();
250 var file = this.options.html_cache_path + '/' + this.http.html_filename;
260 mkdir(path.dirname(file));
27 //异步方式写入缓存
280 fs.writeFile(file, content);
290 return content;
30 },
31 /**
32 * 记录模版文件名
33 * @return {[type]} [description]
34 */
35 recordViewFile: function(){
360 var tplFile = this.http.tpl_file;
370 var key = this.http.group + ':' + this.http.controller + ':' + this.http.action;
380 tplFiles[key] = tplFile;
39 }
40 };
41});
42/**
43 * 获取模版文件
44 * @param {[type]} http [description]
45 * @return {[type]} [description]
46 */
471module.exports.getViewFile = function(http){
480 'use strict';
490 var key = http.group + ':' + http.controller + ':' + http.action;
500 return tplFiles[key];
51};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/App.js

48%
141
68
73
LineHitsSource
11var cluster = require('cluster');
21var fs = require('fs');
31var domain = require('domain');
41var thinkHttp = thinkRequire('Http');
51var Dispatcher = thinkRequire('Dispatcher');
6
7/**
8 * 应用程序
9 * @type {Object}
10 */
111var App = module.exports = Class(function(){
121 'use strict';
13 //controller和action的校验正则
141 var nameReg = /^[A-Za-z\_](\w)*$/;
15 //注释的正则
161 var commentReg = /((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg;
17 //获取形参的正则
181 var parsReg = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
19
201 return {
21 init: function(http){
221 this.http = http;
23 },
24 /**
25 * 解析路由
26 * @return {[type]} [description]
27 */
28 dispatch: function(){
291 return Dispatcher(this.http).run();
30 },
31 /**
32 * 获取controller
33 * @return {[type]} [description]
34 */
35 getController: function(){
361 var group = this.http.group;
371 var controller = '';
38 //检测controller名
391 if (nameReg.test(this.http.controller)) {
401 controller = A(group + '/' + this.http.controller, this.http);
411 if (controller) {
421 return controller;
43 }
44 }
45 //controller不存在时调用的魔术方法
460 var controllerConf = C('call_controller');
470 if (controllerConf) {
480 if (isString(controllerConf)) {
490 controllerConf = controllerConf.split(':');
50 }
510 var action = Dispatcher.getAction(controllerConf.pop());
520 controller = Dispatcher.getController(controllerConf.pop());
530 group = Dispatcher.getGroup(controllerConf.pop());
540 controller = A(group + '/' + controller, this.http);
550 if (controller && isFunction(controller[action + C('action_suffix')])) {
560 this.http.group = group;
570 this.http.controller = controller;
580 this.http.action = action;
590 return controller;
60 }
61 }
62 },
63 /**
64 * 执行
65 * @return {[type]} [description]
66 */
67 exec: function(){
681 var controller = this.getController();
691 if (!controller) {
700 var err = new Error('Controller `' + this.http.controller + '` not found. ' + this.http.pathname);
710 return getPromise(err, true);
72 }
731 var self = this;
741 var action = this.http.action;
751 var act = action;
76 //添加action后缀
771 action += C('action_suffix') || '';
78 //检测action名
791 if (!nameReg.test(action)) {
800 return getPromise(new Error('action `' + act + '` is not valid. ' + this.http.pathname), true);
81 }
821 var initReturnPromise = getPromise(controller.__initReturn);
83 //对应的action方法存在
841 if (isFunction(controller[action])) {
85 //方法参数自动绑定,直接从形参里拿到对应的值
861 if (C('url_params_bind')) {
871 var toString = controller[action].toString().replace(commentReg, '');
881 var match = toString.match(parsReg)[1].split(/,/).filter(function(item){
891 return item;
90 });
91 //匹配到形参
921 if (match && match.length) {
930 return initReturnPromise.then(function(){
940 var data = match.map(function(item){
950 return self.http.post[item] || self.http.get[item] || '';
96 });
970 return self.execAction(controller, action, act, data);
98 });
99 }
100 }
1011 return initReturnPromise.then(function(){
1021 return self.execAction(controller, action, act);
103 });
104 }else{
105 //当指定的方法不存在时,调用魔术方法
106 //默认为__call方法
1070 var callMethod = C('call_method');
1080 if (callMethod && isFunction(controller[callMethod])) {
1090 return initReturnPromise.then(function(){
1100 return controller[callMethod](act, action);
111 });
112 }
113 }
1140 return getPromise(new Error('action `' + action + '` not found. ' + self.http.pathname), true);
115 },
116 /**
117 * 执行一个action, 支持before和after的统一操作
118 * 不对每个action都增加一个before和after,而是使用统一的策略
119 * 默认before和after调用名__before和__after
120 * @param {[type]} controller [description]
121 * @param {[type]} action [description]
122 * @param {[type]} act [description]
123 * @param {[type]} data [description]
124 * @return {[type]} [description]
125 */
126 execAction: function(controller, action, act, data){
1271 var promise = getPromise();
128 //before action
1291 var before = C('before_action_name');
1301 if (before && isFunction(controller[before])) {
1310 promise = getPromise(controller[before](act, action));
132 }
1331 return promise.then(function(){
1341 if (data) {
1350 return controller[action].apply(controller, data)
136 }else{
1371 return controller[action]()
138 }
139 }).then(function(){
140 //after action
1411 var after = C('after_action_name');
1421 if (after && isFunction(controller[after])) {
1430 return controller[after](act, action);
144 }
145 });
146 },
147 /**
148 * 发送错误信息
149 * @param {[type]} error [description]
150 * @return {[type]} [description]
151 */
152 sendError: function(error){
1530 var message = isError(error) ? error.stack : error;
1540 var http = this.http;
1550 console.log(message);
1560 if (!http.res) {
1570 return;
158 }
1590 if (APP_DEBUG) {
1600 http.res.statusCode = 500;
1610 http.res.end(message);
162 }else{
1630 http.res.statusCode = 500;
1640 http.setHeader('Content-Type', 'text/html; charset=' + C('encoding'));
1650 var readStream = fs.createReadStream(C('error_tpl_path'));
1660 readStream.pipe(http.res);
1670 readStream.on('end', function(){
1680 http.res.end();
169 });
170 }
171 }
172 };
173});
174
175/**
176 * run
177 * @return {[type]} [description]
178 */
1791App.run = function(){
1801 'use strict';
1811 return App.mode[APP_MODE]();
182};
183/**
184 * 不同模式下的run
185 * @type {Object}
186 */
1871App.mode = {
188 //命令行模式
189 cli: function(){
1901 'use strict';
1911 var defaultHttp = thinkHttp.getDefaultHttp(process.argv[2]);
1921 thinkHttp(defaultHttp.req, defaultHttp.res).run(App.listener);
193 },
194 //HTTP模式
195 http: function(){
1960 'use strict';
1970 var clusterNums = C('use_cluster');
198 //不使用cluster
1990 if (!clusterNums) {
2000 return App.createServer();
201 }
202 //使用cpu的个数
2030 if (clusterNums === true) {
2040 clusterNums = require('os').cpus().length;
205 }
2060 if (cluster.isMaster) {
2070 for (var i = 0; i < clusterNums; i++) {
2080 cluster.fork();
209 }
2100 cluster.on('exit', function(worker) {
2110 console.log('worker ' + worker.process.pid + ' died');
2120 process.nextTick(function(){
2130 cluster.fork();
214 });
215 });
216 }else {
2170 App.createServer();
218 }
219 }
220};
221/**
222 * 创建服务
223 * @return {[type]} [description]
224 */
2251App.createServer = function(){
2260 'use strict';
227 //自定义创建server
2280 var createServerFn = C('create_server_fn');
2290 if (createServerFn) {
2300 if (isFunction(createServerFn)) {
2310 return createServerFn(App);
2320 }else if (isFunction(global[createServerFn])) {
2330 return global[createServerFn](App);
234 }
235 }
2360 var server = require('http').createServer(function (req, res) {
2370 thinkHttp(req, res).run(App.listener);
238 });
2390 thinkRequire('WebSocket')(server, App).run();
2400 server.listen(C('port'));
241}
242/**
243 * 监听回调函数
244 * @param {[type]} http [description]
245 * @return {[type]} [description]
246 */
2471App.listener = function(http){
2481 'use strict';
249 //自动发送thinkjs和版本的header
2501 http.setHeader('X-Powered-By', 'thinkjs-' + THINK_VERSION);
251 //禁止远程直接用带端口的访问,websocket下允许
2521 if (C('use_proxy') && http.host !== http.hostname && !http.websocket) {
2530 http.res.statusCode = 403;
2540 http.res.end();
2550 return getDefer().promise;
256 }
2571 var instance = App(http);
2581 var domainInstance = domain.create();
2591 var deferred = getDefer();
2601 domainInstance.on('error', function(err){
2610 instance.sendError(err);
2620 deferred.reject(err);
263 });
2641 domainInstance.run(function(){
2651 return tag('app_init', http).then(function(){
2661 return instance.dispatch();
267 }).then(function(){
2681 return tag('app_begin', http);
269 }).then(function(){
2701 return tag('action_init', http);
271 }).then(function(){
2721 return instance.exec();
273 }).then(function(){
2741 return tag('app_end', http);
275 }).catch(function(err){
2760 instance.sendError(err);
277 }).then(function(){
2781 deferred.resolve();
279 })
280 });
2811 return deferred.promise;
282};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Controller.js

11%
151
18
133
LineHitsSource
1/**
2 * Controller 基类
3 * @return {[type]} [description]
4 */
51var fs = require('fs');
61var path = require('path');
71var url = require('url');
8
91module.exports = Class(function() {
101 'use strict';
11 //callback正则
121 var callbackReg = /[^\w\.]/g;
13
141 return {
15 /**
16 * 初始化执行方法
17 * @param {[type]} http [description]
18 * @return {[type]} [description]
19 */
20 init: function(http) {
211 this.http = http;
221 this.view = null;
23 //将http数据打到模版里
241 this.assign('http', this.http);
25 //将配置信息打到模版里
261 this.assign('config', C());
27 //设置变量别名
281 this.set = this.assign;
29 },
30 /**
31 * 获取客户端的ip
32 * @return {[type]} [description]
33 */
34 ip: function() {
350 return this.http.ip();
36 },
37 /**
38 * 实例化View类
39 * @return {[type]} [description]
40 */
41 initView: function() {
423 if (!this.view) {
431 this.view = thinkRequire('View')(this.http);
44 }
453 return this.view;
46 },
47 /**
48 * 是否是GET请求
49 * @return {Boolean} [description]
50 */
51 isGet: function() {
520 return this.http.method === 'GET';
53 },
54 /**
55 * 是否是POST请求
56 * @return {Boolean} [description]
57 */
58 isPost: function() {
590 return this.http.method === 'POST';
60 },
61 /**
62 * 是否是特定METHOD请求
63 * @param {[type]} method [description]
64 * @return {Boolean} [description]
65 */
66 isMethod: function(method) {
670 return this.http.method === method.toUpperCase();
68 },
69 /**
70 * 是否是AJAX请求
71 * @return {Boolean} [description]
72 */
73 isAjax: function(method) {
74 //请求类型判断
750 if (method && this.http.method !== method) {
760 return false;
77 }
780 return this.header('x-requested-with') === 'XMLHttpRequest';
79 },
80 /**
81 * 是否是websocket请求
82 * @return {Boolean} [description]
83 */
84 isWebSocket: function(){
850 return !!this.http.websocket;
86 },
87 /**
88 * 是否是命令行模式
89 * @return {Boolean} [description]
90 */
91 isCli: function(){
920 return APP_MODE === 'cli';
93 },
94 /**
95 * 是否是jsonp接口
96 * @return {Boolean} [description]
97 */
98 isJsonp: function(name){
990 name = name || C('url_callback_name');
1000 return !!this.http.get(name);
101 },
102 /**
103 * 获取QUERY参数
104 * @param {[type]} name [description]
105 * @return {[type]} [description]
106 */
107 get: function(name) {
1080 if (name === undefined) {
1090 return this.http.get;
110 }
1110 return this.http.get[name] || '';
112 },
113 /**
114 * 获取POST参数
115 * @param {[type]} name [description]
116 * @return {[type]} [description]
117 */
118 post: function(name) {
1190 var http = this.http;
1200 if (http.postPromise) {
1210 return http.postPromise.then(function(data){
1220 return name ? (data[name] || '') : data;
123 })
124 }
1250 return name ? (http.post[name] || '') : http.post;
126 },
127 /**
128 * 获取参数
129 * @param {[type]} name [description]
130 * @return {[type]} [description]
131 */
132 param: function(name) {
1330 return this.post(name) || this.get(name);
134 },
135 /**
136 * 获取上传的文件
137 * @param {[type]} name [description]
138 * @return {[type]} [description]
139 */
140 file: function(name) {
1410 var http = this.http;
1420 if (http.postPromise) {
1430 return http.postPromise.then(function(){
1440 return name ? (http.file[name] || '') : http.file;
145 })
146 }
1470 return name ? (http.file[name] || '') : http.file;
148 },
149 /**
150 * header操作
151 * @param {[type]} name [description]
152 * @param {[type]} value [description]
153 * @return {[type]} [description]
154 */
155 header: function(name, value) {
1560 if (name === undefined) {
1570 return this.http.headers;
1580 }else if (isObject(name)) {
1590 for (var key in name) {
1600 this.header(key, name[key]);
161 }
1620 return this;
1630 }else if (value !== undefined) {
1640 this.http.setHeader(name, value);
1650 return this;
166 }else{
1670 return this.http.getHeader(name);
168 }
169 },
170 /**
171 * 获取userAgent
172 * @return {[type]} [description]
173 */
174 userAgent: function(){
1750 return this.http.headers['user-agent'] || '';
176 },
177 /**
178 * 获取referrer
179 * @return {[type]} [description]
180 */
181 referer: function(host){
1820 var referer = this.http.headers.referer || this.http.headers.referfer || '';
1830 if (!referer || !host) {
1840 return referer;
185 }
1860 var info = url.parse(referer);
1870 return info.hostname;
188 },
189 /**
190 * cookie操作
191 * @param {[type]} name [description]
192 * @param {[type]} value [description]
193 * @param {[type]} options [description]
194 * @return {[type]} [description]
195 */
196 cookie: function(name, value, options) {
1970 if (value !== undefined) {
1980 this.http.setCookie(name, value, options);
1990 return this;
200 }
2010 return name === undefined ? this.http.cookie : (this.http.cookie[name] || '');
202 },
203 /**
204 * session
205 * 如果是get操作,则返回一个promise
206 * @param {[type]} name [description]
207 * @param {[type]} value [description]
208 * @return {[type]} [description]
209 */
210 session: function(name, value) {
2110 thinkRequire('Session').start(this.http);
2120 var instance = this.http.session;
2130 if (name === undefined) {
2140 return instance.rm();
215 }
2160 if (value !== undefined) {
2170 return instance.set(name, value);
218 }
2190 return instance.get(name);
220 },
221 /**
222 * 跳转,返回一个pendding promise阻止后面继续执行
223 * @param {[type]} url [description]
224 * @param {[type]} code [description]
225 * @return {[type]} [description]
226 */
227 redirect: function(url, code) {
2280 this.http.redirect(url, code);
2290 return getDefer().promise;
230 },
231 /**
232 * 赋值变量到模版
233 * @param {[type]} name [description]
234 * @param {[type]} value [description]
235 * @return {[type]} [description]
236 */
237 assign: function(name, value) {
2382 if (arguments.length === 1) {
2390 return this.initView().assign(name);
240 }
2412 return this.initView().assign(name, value);
242 },
243 /**
244 * 获取解析后的模版内容
245 * @param {[type]} templateFile [description]
246 * @param {[type]} content [description]
247 * @return {[type]} [description]
248 */
249 fetch: function(templateFile, content) {
2500 return this.initView().fetch(templateFile, content);
251 },
252 /**
253 * 输出模版内容
254 * @param {[type]} templateFile [description]
255 * @param {[type]} charset [description]
256 * @param {[type]} contentType [description]
257 * @param {[type]} content [description]
258 * @return {[type]} [description]
259 */
260 display: function(templateFile, charset, contentType, content) {
2611 return this.initView().display(templateFile, charset, contentType, content);
262 },
263 /**
264 * 调用另一个controll里的aciton
265 * 可以跨分组
266 * A('Admin/Test/index')
267 * @param {[type]} action [description]
268 * @return {[type]} [description]
269 */
270 action: function(action, data) {
271 //自动补group
2720 if (action.split(':').length === 2) {
2730 action = this.http.group + ':' + action;
274 }
2750 return A(action, this.http, data);
276 },
277 /**
278 * jsonp格式输出
279 * @param {[type]} data [description]
280 * @param {[type]} jsonp [description]
281 * @return {[type]} [description]
282 */
283 jsonp: function(data) {
2840 this.type(C('json_content_type'));
2850 var callback = this.get(C('url_callback_name'));
286 //过滤callback值里的非法字符
2870 callback = callback.replace(callbackReg, '');
2880 if (callback) {
2890 this.echo(callback + '(');
2900 this.echo(data);
2910 this.end(')');
292 } else {
2930 this.end(data);
294 }
295 },
296 /**
297 * json格式输出
298 * @param {[type]} data [description]
299 * @return {[type]} [description]
300 */
301 json: function(data){
3020 this.type(C('json_content_type'));
3030 return this.end(data);
304 },
305 /**
306 * 设置http响应状态码
307 * @param {[type]} status [description]
308 * @return {[type]} [description]
309 */
310 status: function(status) {
3110 var res = this.http.res;
3120 if (!res.headersSent) {
3130 res.statusCode = status || 404;
314 }
3150 return this;
316 },
317 /**
318 * 阻止访问
319 * @param {[type]} status [description]
320 * @return {[type]} [description]
321 */
322 deny: function(status){
3230 var res = this.http.res;
3240 if (!res.headersSent) {
3250 res.statusCode = status || 403;
3260 this.http.end();
327 }
3280 return getDefer().promise;
329 },
330 /**
331 * 输出内容
332 * 自动JSON.stringify
333 * 自定将数字等转化为字符串
334 * @param {[type]} obj [description]
335 * @return {[type]} [description]
336 */
337 echo: function(obj, encoding) {
338 //自动发送Content-Type的header
3390 if (C('auto_send_content_type')) {
3400 this.type(C('tpl_content_type'));
341 }
3420 return this.http.echo(obj, encoding);
343 },
344 /**
345 * 结束输出,输出完成时一定要调用这个方法
346 * @param {[type]} obj [description]
347 * @return {[type]} [description]
348 */
349 end: function(obj, encoding) {
3500 if (obj) {
3510 this.echo(obj, encoding);
352 }
3530 this.http.end();
354 },
355 /**
356 * 发送Content-Type
357 * @param {[type]} type [description]
358 * @return {[type]} [description]
359 */
360 type: function(ext){
3610 if (ext.indexOf('/') === -1) {
3620 ext = require('mime').lookup(ext);
363 }
3640 if (!this.http.cthIsSend) {
3650 if (ext.toLowerCase().indexOf('charset=') === -1) {
3660 ext += '; charset=' + C('encoding');
367 }
368 //Content-Type Header has been Send
3690 this.http.cthIsSend = true;
3700 this.http.setHeader('Content-Type', ext);
371 }else{
3720 console.log('Content-Type has been send');
373 }
374 },
375 /**
376 * 下载文件
377 * @return {[type]} [description]
378 */
379 download: function(file, contentType, callback) {
3800 if (isFunction(contentType)) {
3810 callback = contentType;
3820 contentType = '';
383 }
3840 if (!contentType || contentType.indexOf('/') === -1) {
3850 contentType = require('mime').lookup(contentType || file);
386 }
3870 var http = this.http;
3880 var fileStream = fs.createReadStream(file);
3890 this.type(contentType);
3900 http.setHeader('Content-Disposition', 'attachment; filename="' + path.basename(file) + '"');
3910 fileStream.pipe(http.res);
3920 fileStream.on('end', function() {
3930 http.end();
3940 return callback && callback();
395 });
396 },
397 /**
398 * 正常json数据输出
399 * @param {[type]} data [description]
400 * @return {[type]} [description]
401 */
402 success: function(data){
4030 var obj = getObject([C('error_no_key'), C('error_msg_key')], [0, '']);
4040 if (data !== undefined) {
4050 obj.data = data;
406 }
4070 this.type(C('json_content_type'));
4080 this.end(obj);
4090 return getDefer().promise;
410 },
411 /**
412 * 异常json数据数据
413 * @param {[type]} errno [description]
414 * @param {[type]} errmsg [description]
415 * @param {[type]} extra [description]
416 * @return {[type]} [description]
417 */
418 error: function(errno, errmsg, data){
4190 var obj;
4200 if (isObject(errno)) {
4210 data = errmsg;
4220 obj = extend({}, errno);
423 }else{
4240 if (!isNumber(errno)) {
4250 data = errmsg;
4260 errmsg = errno;
4270 errno = C('error_no_default_value');
428 }
4290 obj = getObject([C('error_no_key'), C('error_msg_key')], [errno, errmsg]);
430 }
4310 if (data !== undefined) {
4320 obj.data = data;
433 }
4340 this.type(C('json_content_type'));
4350 this.end(obj);
4360 return getDefer().promise;
437 },
438 /**
439 * 发送执行时间
440 * @param {[type]} name [description]
441 * @return {[type]} [description]
442 */
443 sendTime: function(name){
4440 return this.http.sendTime(name);
445 },
446 /**
447 * 对数据进行过滤
448 * @param {[type]} data [description]
449 * @param {[type]} type [description]
450 * @return {[type]} [description]
451 */
452 filter: function() {
4530 var filter = thinkRequire('Filter').filter;
4540 return filter.apply(null, arguments);
455 },
456 /**
457 * 校验一个值是否合法
458 * @param {[type]} data [description]
459 * @param {[type]} validType [description]
460 * @return {[type]} [description]
461 */
462 valid: function(data, validType) {
463 //单个值检测,只返回是否正常
4640 if (validType !== undefined) {
4650 data = [{
466 value: data,
467 valid: validType
468 }];
4690 var result = thinkRequire('Valid').check(data);
4700 return result.length === 0;
471 }
4720 return thinkRequire('Valid').check(data);
473 }
474 };
475});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Db.js

2%
346
10
336
LineHitsSource
11var url = require('url');
21var querystring = require('querystring');
3/**
4 * 数据库基类
5 * @return {[type]} [description]
6 */
71var Db = module.exports = Class(function(){
81 'use strict';
9 //用于查询的sql语句,所有select语句根据该语句解析
101 var selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%';
11 //where条件里的表达式
121 var comparison = {
13 'EQ': '=',
14 'NEQ': '!=',
15 '<>': '!=',
16 'GT': '>',
17 'EGT': '>=',
18 'LT': '<',
19 'ELT': '<=',
20 'NOTLIKE': 'NOT LIKE',
21 'LIKE': 'LIKE',
22 'IN': 'IN',
23 'NOTIN': 'NOT IN'
24 };
251 return {
26 // 数据库类型
27 dbType: null,
28 // 当前操作所属的模型名
29 model: '_think_',
30 // 当前SQL指令
31 queryStr: '',
32 // 操作的sql列表
33 modelSql: [],
34 // 数据库连接ID 支持多个连接
35 linkIds: [],
36 // 当前连接ID
37 linkId: null,
38 // 是否已经连接数据库
39 connected: false,
40 // 数据库连接参数配置
41 config: '',
42 /**
43 * 初始化,类似于constrcut,类实例化时自动调用
44 * @return {[type]} [description]
45 */
46 init: function(){
47
48 },
49 /**
50 * 连接数据库
51 * @return {[type]} [description]
52 */
53 initConnect: function(){
540 if (!this.connected) {
550 this.linkId = this.connect();
56 }
57 },
58 /**
59 * 解析set集合
60 * @param {[type]} data [description]
61 * @return {[type]} [description]
62 */
63 parseSet: function(data){
640 data = data || {};
650 var set = [];
660 for(var key in data){
670 var value = this.parseValue(data[key]);
680 if (isScalar(value)) {
690 set.push(this.parseKey(key) + '=' + value);
70 }
71 }
720 return ' SET ' + set.join(',');
73 },
74 /**
75 * 解析字段名,具体的数据库里实现
76 * @param {[type]} key [description]
77 * @return {[type]} [description]
78 */
79 parseKey: function(key){
800 return key;
81 },
82 /**
83 * value分析
84 * @param {[type]} value [description]
85 * @return {[type]} [description]
86 */
87 parseValue: function(value){
880 if (isString(value)) {
890 value = '\'' + this.escapeString(value) + '\'';
900 }else if(isArray(value)){
910 if ((value[0] + '').toLowerCase() === 'exp') {
920 value = this.escapeString(value[1]);
93 }else{
940 var self = this;
950 value = value.map(function(item){
960 return self.parseValue(item);
97 });
98 }
990 }else if(isBoolean(value)){
1000 value = value ? '1' : '0';
1010 }else if (value === null) {
1020 value = 'null';
103 }
1040 return value;
105 },
106 /**
107 * field分析
108 * parseField('name');
109 * parseField('name,email');
110 * parseField({
111 * xx_name: 'name',
112 * xx_email: 'email'
113 * })
114 * @return {[type]} [description]
115 */
116 parseField: function(fields){
1170 if (isString(fields) && fields.indexOf(',') > -1) {
1180 fields = fields.split(',');
119 }
1200 if (isArray(fields)) {
1210 var self = this;
1220 return fields.map(function(item){
1230 return self.parseKey(item);
124 }).join(',');
1250 }else if(isObject(fields)){
1260 var data = [];
1270 for(var key in fields){
1280 data.push(this.parseKey(key) + ' AS ' + this.parseKey(fields[key]));
129 }
1300 return data.join(',');
1310 }else if(isString(fields) && fields){
1320 return this.parseKey(fields);
133 }
1340 return '*';
135 },
136 /**
137 * table别名分析
138 * @param {[type]} tables [description]
139 * @return {[type]} [description]
140 */
141 parseTable: function(tables){
1420 if (isString(tables)) {
1430 tables = tables.split(',');
144 }
1450 if (isArray(tables)) {
1460 var self = this;
1470 return tables.map(function(item){
1480 return self.parseKey(item);
149 }).join(',');
1500 }else if (isObject(tables)) {
1510 var data = [];
1520 for(var key in tables){
1530 data.push(this.parseKey(key) + ' AS ' + this.parseKey(tables[key]));
154 }
1550 return data.join(',');
156 }
1570 return '';
158 },
159 /**
160 * where条件分析
161 * @param {[type]} where [description]
162 * @return {[type]} [description]
163 */
164 parseWhere: function(where){
1650 var whereStr = '';
1660 var self = this;
1670 where = where || {};
1680 if (isString(where)) {
1690 whereStr = where;
170 }else{
171 // 定义逻辑运算规则 例如 OR XOR AND NOT
1720 var oList = ['AND', 'OR', 'XOR'];
1730 var operate = (where._logic + '').toUpperCase();
1740 delete where._logic;
1750 operate = oList.indexOf(operate) > -1 ? ' ' + operate + ' ' : ' AND ';
176 //key值的安全检测正则
1770 var keySafeRegExp = /^[\w\|\&\-\.\(\)\,]+$/;
1780 var multi = where._multi;
1790 delete where._multi;
180
1810 var val;
1820 var fn = function(item, i){
1830 var v = multi ? val[i] : val;
1840 return '(' + self.parseWhereItem(self.parseKey(item), v) + ')';
185 };
1860 for(var key in where){
1870 key = key.trim();
1880 val = where[key];
1890 whereStr += '( ';
1900 if (key.indexOf('_') === 0) {
191 // 解析特殊条件表达式
1920 whereStr += this.parseThinkWhere(key, val);
193 }else{
1940 if (!keySafeRegExp.test(key)) {
1950 console.log(key + ' is not safe');
1960 continue;
197 }
1980 var arr;
199 // 支持 name|title|nickname 方式定义查询字段
2000 if (key.indexOf('|') > -1) {
2010 arr = key.split('|');
2020 whereStr += arr.map(fn).join(' OR ');
2030 }else if (key.indexOf('&') > -1) {
2040 arr = key.split('&');
2050 whereStr += arr.map(fn).join(' AND ');
206 }else{
2070 whereStr += this.parseWhereItem(this.parseKey(key), val);
208 }
209 }
2100 whereStr += ' )' + operate;
211 }
2120 whereStr = whereStr.substr(0, whereStr.length - operate.length);
213 }
214
2150 return whereStr ? (' WHERE ' + whereStr) : '';
216 },
217 /**
218 * 解析单个查询条件
219 * @param {[type]} key [description]
220 * @param {[type]} val [description]
221 * @return {[type]} [description]
222 */
223 parseWhereItem: function(key, val){
2240 if (!isArray(val)) {
225 //对字符串类型字段采用模糊匹配
2260 if (C('db_like_fields').indexOf(key) > -1) {
2270 return key + ' LIKE ' + this.parseValue('%' + val + '%');
228 }else{
2290 return key + ' = ' + this.parseValue(val);
230 }
231 }
2320 var whereStr = '';
2330 var data;
2340 if (isString(val[0])) {
2350 var val0 = val[0].toUpperCase();
2360 val0 = comparison[val0] || val0;
2370 if (/^(=|!=|>|>=|<|<=)$/.test(val0)) { // 比较运算
2380 whereStr += key + ' ' + val0 + ' ' + this.parseValue(val[1]);
2390 }else if (/^(NOT\s+LIKE|LIKE)$/.test(val0)) { // 模糊查找
2400 if (isArray(val[1])) {
2410 var likeLogic = (val[2] ? val[2] : 'OR').toUpperCase();
2420 var likesLogic = ['AND','OR','XOR'];
2430 if (likesLogic.indexOf(likeLogic) > -1) {
2440 var like = val[1].map(function(item){
2450 return key + ' ' + val0 + ' ' + this.parseValue(item);
246 }).join(likeLogic);
2470 whereStr += '(' + like + ')';
248 }
249 }else{
2500 whereStr += key + ' ' + val0 + ' ' + this.parseValue(val[1]);
251 }
2520 }else if(val0 === 'EXP'){ // 使用表达式
2530 whereStr += '(' + key + ' ' + val[1] + ')';
2540 }else if(val0 === 'IN' || val0 === 'NOT IN'){ // IN 运算
2550 if (val[2] === 'exp') {
2560 whereStr += key + ' ' + val0 + ' ' + val[1];
257 }else{
2580 if (isString(val[1])) {
2590 val[1] = val[1].split(',');
260 }
2610 val[1] = this.parseValue(val[1]);
262 //如果只有一个值,那么变成=或者!=
2630 if (val[1].length === 1) {
2640 whereStr += key + (val0 === 'IN' ? ' = ' : ' != ') + val[1];
265 }else{
2660 whereStr += key + ' ' + val0 + ' (' + val[1].join(',') + ')';
267 }
268 }
2690 }else if(val0 === 'BETWEEN'){ // BETWEEN运算
2700 data = isString(val[1]) ? val[1].split(',') : val[1];
2710 if (!isArray(data)) {
2720 data = [val[1], val[2]];
273 }
2740 whereStr += ' (' + key + ' ' + val0 + ' ' + this.parseValue(data[0]);
2750 whereStr += ' AND ' + this.parseValue(data[1]) + ')';
276 }else{
2770 console.log('_EXPRESS_ERROR_', key, val);
2780 return '';
279 }
280 }else{
2810 var length = val.length;
2820 var rule = val[val.length - 1] || '';
2830 if (rule && ['AND','OR','XOR'].indexOf(rule) > -1) {
2840 length = length - 1;
285 }else{
2860 rule = 'AND';
287 }
2880 for(var i = 0; i < length; i++){
2890 data = isArray(val[i]) ? val[i][1] : val[i];
2900 var exp = ((isArray(val[i]) && val[i][0]) + '').toLowerCase();
2910 if (exp === 'exp') {
2920 whereStr += '(' + key + ' ' + data + ') ' + rule + ' ';
293 }else{
2940 var op = isArray(val[i]) ? comparison[val[i][0].toUpperCase()] : '=';
2950 whereStr += '(' + key + ' ' + op + ' ' + this.parseValue(data) + ') ' + rule + ' ';
296 }
297 }
2980 whereStr = whereStr.substr(0, whereStr.length - 4);
299 }
3000 return whereStr;
301 },
302 /**
303 * 解析一些特殊的where条件
304 * @param {[type]} key [description]
305 * @param {[type]} val [description]
306 * @return {[type]} [description]
307 */
308 parseThinkWhere: function(key, val){
3090 switch(key){
310 // 字符串模式查询条件
311 case '_string':
3120 return val;
313 // 复合查询条件
314 case '_complex':
3150 return this.parseWhere(val).substr(6);
316 // 字符串模式查询条件
317 case '_query':
3180 var where = querystring.parse(val);
3190 var op = ' AND ';
3200 if ('_logic' in where) {
3210 op = ' ' + where._logic.toLowerCase() + ' ';
3220 delete where._logic;
323 }
3240 var arr = [];
3250 for(var name in where){
3260 val = where[name];
3270 val = this.parseKey(name) + ' = ' + this.parseValue(val);
3280 arr.push(val);
329 }
3300 return arr.join(op);
331 default:
3320 return '';
333 }
3340 return '';
335 },
336 /**
337 * 解析limit,对非法的limit进行过滤
338 * @param {[type]} limit [description]
339 * @return {[type]} [description]
340 */
341 parseLimit: function(limit){
3420 limit = (limit + '').split(',').slice(0, 2);
3430 var flag = limit.every(function(item){
3440 return isNumberString(item);
345 });
3460 if (!flag) {
3470 return '';
348 }
3490 limit = limit.join(',');
3500 return limit ? (' LIMIT ' + limit) : '';
351 },
352 /**
353 * 解析join
354 * @param {[type]} join [description]
355 * @return {[type]} [description]
356 */
357 parseJoin: function(join){
3580 var joinStr = '';
3590 if (!join) {
3600 return '';
361 }
3620 if (isArray(join)) {
3630 join.forEach(function(val){
3640 if (val.toLowerCase().indexOf('join') > -1) {
3650 joinStr += val;
366 }else{
3670 joinStr += ' LEFT JOIN ' + val;
368 }
369 });
370 }else{
3710 joinStr += ' LEFT JOIN ' + join;
372 }
3730 return joinStr;
374 },
375 /**
376 * 解析order
377 * @param {[type]} order [description]
378 * @return {[type]} [description]
379 */
380 parseOrder: function(order){
3810 var self = this;
3820 if (isArray(order)) {
3830 order = order.map(function(item){
3840 return self.parseKey(item);
385 }).join(',');
3860 }else if (isObject(order)) {
3870 var arr = [];
3880 for(var key in order){
3890 var val = order[key];
3900 val = this.parseKey(key) + ' ' + val;
3910 arr.push(val);
392 }
3930 order = arr.join(',');
394 }
3950 return order ? (' ORDER BY ' + order) : '';
396 },
397 /**
398 * 解析group
399 * @param {[type]} group [description]
400 * @return {[type]} [description]
401 */
402 parseGroup: function(group){
4030 return group ? (' GROUP BY ' + group) : '';
404 },
405 /**
406 * 解析having
407 * @param {[type]} having [description]
408 * @return {[type]} [description]
409 */
410 parseHaving: function(having){
4110 return having ? (' HAVING ' + having) : '';
412 },
413 /**
414 * 解析注释,一般情况下用不到
415 * @param {[type]} comment [description]
416 * @return {[type]} [description]
417 */
418 parseComment: function(comment){
4190 return comment ? (' /* ' + comment + '*/') : '';
420 },
421 /**
422 * 解析Distinct
423 * @param {[type]} distinct [description]
424 * @return {[type]} [description]
425 */
426 parseDistinct: function(distinct){
4270 return distinct ? ' Distinct ' : '';
428 },
429 /**
430 * 解析Union
431 * @param {[type]} union [description]
432 * @return {[type]} [description]
433 */
434 parseUnion: function(union){
4350 if (!union) {
4360 return '';
437 }
4380 var str = '';
4390 if ('_all' in union) {
4400 str = 'UNION ALL ';
4410 delete union._all;
442 }else{
4430 str = 'UNION ';
444 }
4450 var sql = [];
4460 for(var key in union){
4470 var val = union[key];
4480 val = str + (isArray(val) ? this.buildSelectSql(val) : val);
4490 sql.push(sql);
450 }
4510 return sql.join(' ');
452 },
453 /**
454 * 解析Lock
455 * @param {[type]} lock [description]
456 * @return {[type]} [description]
457 */
458 parseLock: function(lock){
4590 if (!lock) {
4600 return '';
461 }
4620 return ' FOR UPDATE ';
463 },
464 /**
465 * 将page转化为sql里的limit
466 * @return {[type]} [description]
467 */
468 pageToLimit: function(options){
4690 options = options || {};
470 //根据page生成limit
4710 if ('page' in options) {
4720 var page = options.page + '';
4730 var listRows = 0;
4740 if (page.indexOf(',') > -1) {
4750 page = page.split(',');
4760 listRows = page[1];
4770 page = page[0];
478 }
4790 page = parseInt(page, 10) || 1;
4800 if (!listRows) {
4810 listRows = isNumberString(options.limit) ? options.limit : C('db_nums_per_page');
482 }
4830 var offset = listRows * (page - 1);
4840 options.limit = offset + ',' + listRows;
485 }
4860 return options;
487 },
488 /**
489 * 拼接select查询语句
490 * @param {[type]} options [description]
491 * @return {[type]} [description]
492 */
493 buildSelectSql: function(options){
4940 options = this.pageToLimit(options);
4950 var sql = this.parseSql(selectSql, options);
4960 sql += this.parseLock(options.lock);
4970 return sql;
498 },
499 /**
500 * 解析sql语句
501 * @param {[type]} sql [description]
502 * @param {[type]} options [description]
503 * @return {[type]} [description]
504 */
505 parseSql: function(sql, options){
5060 options = options || {};
5070 var self = this;
5080 return sql.replace(/\%([A-Z]+)\%/g, function(a, type){
5090 type = type.toLowerCase();
5100 return self['parse' + ucfirst(type)](options[type] || '');
511 }).replace(/__([A-Z_-]+)__/g, function(a, b){
5120 return '`' + C('db_prefix') + b.toLowerCase() + '`';
513 });
514 },
515 /**
516 * 插入一条记录
517 * @param {[type]} data [description]
518 * @param {[type]} options [description]
519 * @param {[type]} replace [description]
520 * @return {[type]} [description]
521 */
522 insert: function(data, options, replace){
5230 data = data || {};
5240 options = options || {};
5250 var values = [];
5260 var fields = [];
5270 this.model = options.model;
5280 for(var key in data){
5290 var val = data[key];
5300 val = this.parseValue(val);
5310 if (isScalar(val)) {
5320 values.push(val);
5330 fields.push(this.parseKey(key));
534 }
535 }
5360 var sql = (replace ? 'REPLACE' : 'INSERT') + ' INTO ';
5370 sql += this.parseTable(options.table) + ' (' + fields.join(',') + ') ';
5380 sql += 'VALUES(' + values.join(',') + ')';
5390 sql += this.parseLock(options.lock) + this.parseComment(options.comment);
5400 return this.execute(sql);
541 },
542 /**
543 * 插入多条记录
544 * @param {[type]} data [description]
545 * @param {[type]} options [description]
546 * @param {[type]} replace [description]
547 * @return {[type]} [description]
548 */
549 insertAll: function(data, options, replace){
5500 var fields = Object.keys(data[0]);
5510 var self = this;
5520 fields = fields.map(function(item){
5530 return self.parseKey(item);
554 }).join(',');
5550 var values = data.map(function(item){
5560 var value = [];
5570 for(var key in item){
5580 var val = item[key];
5590 val = self.parseValue(val);
5600 if (isScalar(val)) {
5610 value.push(val);
562 }
563 }
5640 return '(' + value.join(',') + ')';
565 }).join(',');
5660 var sql = replace ? 'REPLACE' : 'INSERT';
5670 sql += ' INTO ' + this.parseTable(options.table) + '(' + fields + ') VALUES ' + values;
5680 return this.execute(sql);
569 },
570 /**
571 * 从一个选择条件的结果插入记录
572 * @param {[type]} fields [description]
573 * @param {[type]} table [description]
574 * @param {[type]} options [description]
575 * @return {[type]} [description]
576 */
577 selectInsert: function(fields, table, options){
5780 options = options || {};
5790 this.model = options.model;
5800 if (isString(fields)) {
5810 fields = fields.split(',');
582 }
5830 var self = this;
5840 fields = fields.map(function(item){
5850 return self.parseKey(item);
586 });
5870 var sql = 'INSERT INTO ' + this.parseTable(options.table) + ' (' + fields.join(',') + ')';
5880 sql += this.buildSelectSql(options);
5890 return this.execute(sql);
590 },
591 /**
592 * 删除记录
593 * @param {[type]} options [description]
594 * @return {[type]} [description]
595 */
596 delete: function(options){
5970 options = options || {};
5980 this.model = options.model;
5990 var sql = [
600 'DELETE FROM ',
601 this.parseTable(options.table),
602 this.parseWhere(options.where),
603 this.parseOrder(options.order),
604 this.parseLimit(options.limit),
605 this.parseLock(options.lock),
606 this.parseComment(options.comment)
607 ].join('');
6080 return this.execute(sql);
609 },
610 /**
611 * 更新数据
612 * @param {[type]} data [description]
613 * @param {[type]} options [description]
614 * @return {[type]} [description]
615 */
616 update: function(data, options){
6170 options = options || {};
6180 this.model = options.model;
6190 var sql = [
620 'UPDATE ',
621 this.parseTable(options.table),
622 this.parseSet(data),
623 this.parseWhere(options.where),
624 this.parseOrder(options.order),
625 this.parseLimit(options.limit),
626 this.parseLock(options.lock),
627 this.parseComment(options.comment)
628 ].join('');
6290 return this.execute(sql);
630 },
631 /**
632 * 数据查询
633 * @todo 返回是个promise,缓存调用需要修改
634 * @param {[type]} options [description]
635 * @return {[type]} [description]
636 */
637 select: function(options){
6380 var sql, cache;
6390 if (isString(options) && options.indexOf('SELECT') > -1) {
6400 sql = options;
6410 cache = arguments[1];
642 }else{
6430 options = options || {};
6440 this.model = options.model;
6450 sql = this.buildSelectSql(options);
6460 cache = options.cache;
647 }
6480 var self = this;
6490 var cacheOn = !isEmpty(cache) && C('db_cache_on');
650 //获取数据
6510 function queryData(){
6520 return self.query(sql).then(function(data){
6530 if (cacheOn) {
6540 S(key, data, cache);
655 }
6560 return data;
657 });
658 }
6590 if (cacheOn) {
6600 var key = isString(cache.key) && cache.key ? cache.key : md5(sql);
6610 return S(key, undefined, cache).then(function(value){
6620 return value || queryData();
663 });
664 }
6650 return queryData();
666 },
667 /**
668 * 转义字符
669 * @param {[type]} str [description]
670 * @return {[type]} [description]
671 */
672 escapeString: function(str){
6730 if (!str) {
6740 return '';
675 }
6760 return str.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
6770 switch(s) {
678 case '\0':
6790 return '\\0';
680 case '\n':
6810 return '\\n';
682 case '\r':
6830 return '\\r';
684 case '\b':
6850 return '\\b';
686 case '\t':
6870 return '\\t';
688 case '\x1a':
6890 return '\\Z';
690 default:
6910 return '\\'+s;
692 }
693 });
694 },
695 /**
696 * 获取上次的sql语句
697 * @param {[type]} model [description]
698 * @return {[type]} [description]
699 */
700 getLastSql: function(model){
7010 return model ? this.modelSql[model] : this.queryStr;
702 },
703 /**
704 * 设置模型
705 * @param {[type]} model [description]
706 */
707 setModel: function(model){
7080 this.model = model;
7090 return this;
710 }
711 };
712});
713/**
714 * 解析dsn
715 * 格式: mysql://username:passwd@localhost:3306/DbName
716 * @param string dsn [description]
717 * @return {[type]} [description]
718 */
7191Db.parseDSN = function(dsn){
7200 'use strict';
7210 if (!dsn) {
7220 return false;
723 }
7240 var info = url.parse(dsn);
7250 var auth = (info.auth || '').split(':');
7260 return {
727 'dbms': info.protocol,
728 'username': auth[0] || '',
729 'password': auth[1] || '',
730 'hostname': info.hostname || '',
731 'hostport': info.port || '',
732 'database': (info.pathname || '').substr(1),
733 'dsn': ''
734 };
735};
736/**
737 * 解析配置
738 * @param {[type]} config [description]
739 * @return {[type]} [description]
740 */
7411Db.parseConfig = function(config){
7420 'use strict';
7430 if (config && isString(config)) {
7440 return this.parseDSN(config);
7450 }else if(isObject(config)){
7460 return {
747 'dbms': config.db_type || 'mysql',
748 'username': config.db_user,
749 'password': config.db_pwd,
750 'hostname': config.db_host,
751 'hostport': config.db_port,
752 'database': config.db_name,
753 'dsn': config.db_dsn,
754 'params': config.db_params
755 };
7560 }else if(!config){
7570 if (C('db_dsn')) {
7580 return this.parseDSN(C('db_dsn'));
759 }
7600 return {
761 'dbms' : C('db_type'),
762 'username' : C('db_user'),
763 'password' : C('db_pwd'),
764 'hostname' : C('db_host'),
765 'hostport' : C('db_port'),
766 'database' : C('db_name'),
767 'dsn' : C('db_dsn'),
768 'params' : C('db_params'),
769 };
770 }
7710 return config;
772};
773/**
774 * 根据配置获取对应的数据库实例
775 * @param {[type]} config [description]
776 * @return {[type]} [description]
777 */
7781Db.getInstance = function(config){
7790 'use strict';
7800 config = this.parseConfig(config);
7810 if (!config.dbms) {
7820 console.log('no dbms config');
7830 return false;
784 }
785 //数据库类型
7860 var dbType = config.dbms.toLowerCase();
7870 dbType = dbType.substr(0, 1).toUpperCase() + dbType.substr(1);
7880 var instance = thinkRequire(dbType + 'Db')(config);
7890 instance.dbType = dbType.toUpperCase();
7900 return instance;
791};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Dispatcher.js

87%
47
41
6
LineHitsSource
1/**
2 * 路由识别
3 * @type {Object}
4 */
51var Dispatcher = module.exports = Class(function(){
61 'use strict';
71 return {
8 /**
9 * 初始化
10 * @param {[type]} http [description]
11 * @return {[type]} [description]
12 */
13 init: function(http){
141 this.http = http;
15 },
16 /**
17 * 准备pathanem
18 * @return {[type]} [description]
19 */
20 preparePathName: function(){
211 var pathname = this.http.pathname.split('/').filter(function(item){
222 return item.trim();
23 }).join('/');
24 //去除pathname前缀
251 var prefix = C('url_pathname_prefix');
261 if (prefix && pathname.indexOf(prefix) === 0) {
270 pathname = pathname.substr(prefix.length);
28 }
29 //判断URL后缀
301 var suffix = C('url_pathname_suffix');
311 if (suffix && pathname.substr(0 - suffix.length) === suffix) {
320 pathname = pathname.substr(0, pathname.length - suffix.length);
33 }
341 this.http.pathname = pathname;
35 },
36 /**
37 * 解析pathname
38 * @return {[type]} [description]
39 */
40 parsePathName: function(){
411 if (this.http.group) {
420 return true;
43 }
441 var paths = this.http.pathname.split('/');
45 //将group list变为小写
461 var groupList = C('app_group_list').map(function(item){
472 return item.toLowerCase();
48 });
491 var group = '';
501 if (groupList.length && paths[0] && groupList.indexOf(paths[0].toLowerCase()) > -1) {
510 group = paths.shift();
52 }
531 var controller = paths.shift();
541 var action = paths.shift();
55 //解析剩余path的参数
561 if (paths.length) {
570 for(var i = 0,length = Math.ceil(paths.length) / 2; i < length; i++){
580 this.http.get[paths[i * 2]] = paths[i * 2 + 1] || '';
59 }
60 }
611 this.http.group = Dispatcher.getGroup(group);
621 this.http.controller = Dispatcher.getController(controller);
631 this.http.action = Dispatcher.getAction(action);
64 },
65 /**
66 * run
67 * @return {[type]} [description]
68 */
69 run: function(){
701 var self = this;
711 return tag('resource_check', this.http).then(function(){
721 return self.preparePathName();
73 }).then(function(){
741 return tag('path_info', self.http);
75 }).then(function(){
761 return tag('route_check', self.http);
77 }).then(function(){
781 return self.parsePathName();
79 });
80 }
81 };
82});
83
84/**
85 * 获取group
86 * @param {[type]} group [description]
87 * @return {[type]} [description]
88 */
891Dispatcher.getGroup = function(group){
901 'use strict';
911 group = group || C('default_group');
921 return ucfirst(group);
93};
94/**
95 * 获取controller
96 * @param {[type]} controller [description]
97 * @return {[type]} [description]
98 */
991Dispatcher.getController = function(controller){
1001 'use strict';
1011 controller = controller || C('default_controller');
1021 return ucfirst(controller);
103};
104/**
105 * 获取action
106 * @param {[type]} action [description]
107 * @return {[type]} [description]
108 */
1091Dispatcher.getAction = function(action){
1101 'use strict';
1111 action = action || C('default_action');
1121 return action;
113};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Http.js

40%
135
55
80
LineHitsSource
1/**
2 * 网络方法处理
3 * @type {Object}
4 */
51var querystring = require('querystring');
61var url = require('url');
71var cookie = thinkRequire('Cookie');
81var EventEmitter = require('events').EventEmitter;
91var multiparty = require('multiparty');
10
111var localIp = '127.0.0.1';
121module.exports = Class(function(){
131 'use strict';
141 var multiReg = /^multipart\/(form-data|related);\s*boundary=(?:"([^"]+)"|([^;]+))$/i;
151 return {
16 init: function(req, res){
171 this.req = req;
181 this.res = res;
191 this.http = new EventEmitter();
20 //记录当前请求的开始时间
211 this.http.startTime = Date.now();
22 },
23 run: function(callback){
241 this._request();
251 this._response();
26 //数组的indexOf要比字符串的indexOf略快
271 var methods = ['POST', 'PUT', 'PATCH'];
281 if (methods.indexOf(this.req.method) > -1) {
290 return this.getPostData(callback);
30 }
311 return callback && callback(this.http);
32 },
33 /**
34 * 检测含有post数据
35 * @return {Boolean} [description]
36 */
37 hasPostData: function(){
380 if ('transfer-encoding' in this.req.headers) {
390 return true;
40 }
410 var contentLength = this.req.headers['content-length'] | 0;
420 return contentLength > 0;
43 },
44 /**
45 * 获取POST过来的数据,包含上传的文件
46 * 依赖multiparty库
47 * @param {Function} callback [description]
48 * @return {[type]} [description]
49 */
50 getPostData: function(callback){
51 //没有post数据,直接回调
520 if (!this.hasPostData()) {
530 return callback && callback(this.http);
54 }
550 var self = this;
560 var contentType = (this.req.headers['content-type'] || '').split(';')[0].trim();
570 var deferred = getDefer();
58 //异步获取post数据
590 var postDataAsync = C('post_data_async');
60 //表单数据提交
610 if (multiReg.test(contentType)) {
620 var form = new multiparty.Form({
63 maxFieldsSize: C('post_max_fields_size'),
64 maxFields: C('post_max_fields'),
65 maxFilesSize: C('post_max_file_size')
66 });
670 form.on('file', function(name, value){
680 self.http.file[name] = value;
69 });
700 form.on('field', function(name, value){
710 self.http.post[name] = value;
72 });
730 form.on('close', function(){
740 if (postDataAsync) {
750 return deferred.resolve(self.http.post);
76 }
770 return callback && callback(self.http);
78 });
79 //有错误后直接拒绝当前请求
800 form.on('error', function(){
810 self.res.statusCode = 413;
820 self.res.end();
83 });
840 form.parse(this.req);
85 }else{
860 var buffer = '';
870 this.req.setEncoding(C('encoding'));
880 this.req.on('data', function(chunk){
890 buffer += chunk;
90 });
910 this.req.on('end', function(){
92 //json数据格式
930 var jsonConentType = C('post_json_content_type');
940 if (!isArray(jsonConentType)) {
950 jsonConentType = [jsonConentType];
96 }
970 if (jsonConentType.indexOf(contentType) > -1) {
980 self.http.post = JSON.parse(buffer) || {};
99 }else{
1000 self.http.post = querystring.parse(buffer) || {};
101 }
102 //请求内容
1030 self.http.payload = buffer;
1040 if (postDataAsync) {
1050 return deferred.resolve(self.http.post);
106 }
1070 return callback && callback(self.http);
108 });
109 }
1100 if (postDataAsync) {
1110 self.http.postPromise = deferred.promise;
1120 return callback && callback(self.http);
113 }
114 },
115 _request: function(){
1161 var req = {
117 version: this.req.httpVersion,
118 method: this.req.method,
119 headers: this.req.headers,
120 getHeader: function(name){
1210 return this.headers[name] || '';
122 },
123 post: {},
124 file: {},
125 ip: function(){
1260 var ip = this.req.connection.remoteAddress || this.req.socket.remoteAddress;
1270 if (ip && ip !== localIp) {
1280 return ip;
129 }
1300 return this.headers['x-forwarded-for'] || this.headers['x-real-ip'] || localIp;
131 },
132 cookie: cookie.parse(this.req.headers.cookie || '')
133 };
1341 extend(this.http, req);
135
136 //解析url中的参数
1371 var urlInfo = url.parse('//' + req.headers.host + this.req.url, true, true);
1381 this.http.pathname = urlInfo.pathname;
139 //query只记录?后面的参数
1401 this.http.query = urlInfo.query;
141 //get包含路由解析追加的参数
1421 this.http.get = extend({}, urlInfo.query);
143 //主机名,带端口
1441 this.http.host = urlInfo.host;
145 //主机名,不带端口
1461 this.http.hostname = urlInfo.hostname;
147 //将原生的request对象放在http上,方便后续在controller等地方使用
1481 this.http.req = this.req;
149 },
150 _response: function(){
1511 var res = {
152 /**
153 * 一次请求下,可能会发送多个Cookie,所以这里不能立即发送
154 * 需要临时存起来,到输出内容前统一发送
155 * @type {Object}
156 */
157 _cookie: {},
158 /**
159 * 发送header
160 * @param {[type]} name [description]
161 * @param {[type]} value [description]
162 */
163 setHeader: function(name, value){
1642 if (this.res.headersSent) {
1650 if (APP_DEBUG) {
1660 console.log('headers has been sent.', name, value);
167 }
1680 return;
169 }
1702 this.res.setHeader(name, value);
171 },
172 /**
173 * 设置cookie
174 * @param {[type]} name [description]
175 * @param {[type]} value [description]
176 * @param {[type]} options [description]
177 */
178 setCookie: function(name, value, options){
1790 options = options || {};
1800 if (typeof options === 'number') {
1810 options = {timeout: options};
182 }
1830 var timeout = options.timeout;
1840 if (timeout === undefined) {
1850 timeout = C('cookie_timeout');
186 }
1870 delete options.timeout;
188 //if value is null, remove cookie
1890 if (value === null) {
1900 timeout = -1000;
191 }
1920 var defaultOptions = {
193 path: C('cookie_path'),
194 domain: C('cookie_domain'),
195 expires: new Date (Date.now() + timeout * 1000)
196 };
1970 if (timeout === 0) {
1980 delete defaultOptions.expires;
199 }
2000 for(var key in options){
2010 defaultOptions[key.toLowerCase()] = options[key];
202 }
2030 defaultOptions.name = name;
2040 defaultOptions.value = encodeURIComponent(value + '');
2050 this._cookie[name] = defaultOptions;
206 },
207 /**
208 * 将队列中的cookie发送出去
209 * @return {[type]} [description]
210 */
211 sendCookie: function(){
2122 var cookies = Object.values(this._cookie).map(function(item){
2130 return cookie.stringify(item.name, item.value, item);
214 });
2152 if (cookies.length) {
2160 this.setHeader('Set-Cookie', cookies);
217 //发送Cookie后不清除_cookie内容,websocket里需要读取
218 //this._cookie = {};
219 }
220 },
221 /**
222 * url跳转
223 * @param {[type]} url [description]
224 * @param {[type]} code [description]
225 * @return {[type]} [description]
226 */
227 redirect: function(url, code){
2280 this.res.statusCode = code || 302;
2290 this.setHeader('Location', url || '/');
2300 this.end();
231 },
232 /**
233 * 发送执行时间
234 * @param {[type]} name [description]
235 * @return {[type]} [description]
236 */
237 sendTime: function(name){
2380 var time = Date.now() - this.startTime;
2390 this.setHeader('X-' + name, time + 'ms');
240 },
241 /**
242 * 输出内容
243 * @param {[type]} obj [description]
244 * @param {[type]} encoding [description]
245 * @return {[type]} [description]
246 */
247 echo: function(obj, encoding){
2481 this.sendCookie();
2491 if (isArray(obj) || isObject(obj)) {
2500 obj = JSON.stringify(obj);
251 }
2521 if (!isString(obj) && !(obj instanceof Buffer)) {
2530 obj += '';
254 }
2551 this.res.write(obj, encoding || C('encoding'));
256 },
257 /**
258 * 结束URL
259 * @return {[type]} [description]
260 */
261 end: function(){
2621 this.emit('beforeEnd', this);
2631 this.sendCookie();
2641 this.res.end();
2651 this.emit('afterEnd', this);
266 }
267 };
2681 extend(this.http, res);
269 //将原生的response对象放在http上,方便后续controller等地方使用
2701 this.http.res = this.res;
271 }
272 };
273});
274/**
275 * 获取默认的http信息
276 * @param {[type]} data [description]
277 * @return {[type]} [description]
278 */
2791module.exports.getDefaultHttp = function(data){
2802 'use strict';
2812 data = data || {};
2822 if (isString(data)) {
2832 if (data[0] === '{') {
2840 data = JSON.parse(data);
2852 }else if (/^[\w]+\=/.test(data)) {
2860 data = querystring.parse(data);
287 }else{
2882 data = {url: data};
289 }
290 }
2912 var fn = function(){
2924 return '';
293 };
2942 var url = data.url || '';
2952 if (url.indexOf('/') !== 0) {
2960 url = '/' + url;
297 }
2982 return {
299 req: {
300 httpVersion: '1.1',
301 method: data.method || 'GET',
302 url: url,
303 headers: extend({
304 host: data.host || localIp
305 }, data.headers || {}),
306 connection: {
307 remoteAddress: data.ip || localIp
308 }
309 },
310 res: {
311 end: data.end || data.close || fn,
312 write: data.write || data.send || fn,
313 setHeader: fn
314 }
315 };
316};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Model.js

5%
440
24
416
LineHitsSource
11var util = require('util');
21var querystring = require('querystring');
3
4//数据库实例化对象
51var dbInstances = {};
6//数据表的字段信息
71var tableFields = {};
8//db缓存数据
91var dbCacheData = {};
10
11/**
12 * Model类
13 * @type {[type]}
14 */
151var Model = module.exports = Class(function(){
161 'use strict';
17 //解析page参数
181 var parsePage = function(options){
190 if ('page' in options) {
200 var page = options.page + '';
210 var num = 0;
220 if (page.indexOf(',') > -1) {
230 page = page.split(',');
240 num = parseInt(page[1], 10);
250 page = page[0];
26 }
270 num = num || C('db_nums_per_page');
280 page = parseInt(page, 10) || 1;
290 return {
30 page: page,
31 num: num
32 };
33 }
340 return {
35 page: 1,
36 num: C('db_nums_per_page')
37 };
38 };
39 /**
40 * 字符串命名风格转换
41 * @param {[type]} name [description]
42 * @param {[type]} type [description]
43 * @return {[type]} [description]
44 */
451 var parseName = function(name, type){
460 name = (name + '').trim();
470 if (type) {
480 name = name.replace(/_([a-zA-Z])/g, function(a, b){
490 return b.toUpperCase();
50 });
510 return name.substr(0, 1).toUpperCase() + name.substr(1);
52 } else {
53 //首字母如果是大写,不转义为_x
540 if (name.length >= 1) {
550 name = name.substr(0, 1).toLowerCase() + name.substr(1);
56 }
570 return name.replace(/[A-Z]/g, function(a){
580 return '_' + a;
59 }).toLowerCase();
60 }
61 };
62
631 return {
64 // 当前数据库操作对象
65 db: null,
66 // 主键名称
67 pk: 'id',
68 // 数据表前缀
69 tablePrefix: '',
70 // 数据库配置信息
71 config: null,
72 // 配置信息key
73 configKey: '',
74 // 模型名称
75 name: '',
76 // 数据库名称
77 dbName: '',
78 // 数据表名(不包含表前缀)
79 tableName: '',
80 // 实际数据表名(包含表前缀)
81 trueTableName: '',
82 // 数据表子度信息
83 fields: {},
84 // 数据信息
85 _data: {},
86 // 参数
87 _options: {},
88 /**
89 * 取得DB类的实例对象 字段检查
90 * @access public
91 * @param string $name 模型名称
92 * @param string $tablePrefix 表前缀
93 * @param mixed config 数据库连接信息
94 */
95 init: function(name, tablePrefix, config){
96 // 获取模型名称
970 if (name) {
980 if (name.indexOf('.') > -1) {
990 name = name.split('.');
1000 this.dbName = name[0];
1010 this.name = name[1];
102 }else{
1030 this.name = name;
104 }
1050 }else if(!this.name){
1060 this.getModelName();
107 }
1080 if (!isString(tablePrefix)) {
1090 config = tablePrefix;
1100 tablePrefix = undefined;
111 }
1120 this.config = config || '';
113 //设置数据表前缀
1140 if (tablePrefix || this.config.db_prefix) {
1150 this.tablePrefix = tablePrefix || this.config.db_prefix;
116 }else{
1170 if (!this.tablePrefix) {
1180 this.tablePrefix = C('db_prefix');
119 }
120 }
121 //子类的init方法
1220 if (this._init) {
1230 this._init();
124 }
125 },
126 /**
127 * 初始化数据库连接
128 * @access public
129 * @param integer $linkNum 连接序号
130 * @param mixed $config 数据库连接信息
131 * @param array $params 模型参数
132 * @return Model
133 */
134 initDb: function(){
1350 if (this.db) {
1360 return this.db;
137 }
1380 var config = this.config;
1390 var configKey = md5(JSON.stringify(config));
1400 if (!dbInstances[configKey]) {
1410 if (config && isString(config) && config.indexOf('/') === -1) {
1420 config = C(config);
143 }
1440 dbInstances[configKey] = thinkRequire('Db').getInstance(config);
145 }
1460 this.db = dbInstances[configKey];
1470 this.configKey = configKey;
1480 return this.db;
149 },
150 /**
151 * 获取模型名
152 * @access public
153 * @return string
154 */
155 getModelName: function(){
1560 if (this.name) {
1570 return this.name;
158 }
1590 var filename = this.__filename || __filename;
1600 var name = filename.split('/').pop();
1610 this.name = name.substr(0, name.length - 8);
1620 return this.name;
163 },
164 /**
165 * 获取表名
166 * @return {[type]} [description]
167 */
168 getTableName: function(){
1690 var tableName;
1700 if (!this.trueTableName) {
1710 tableName = this.tablePrefix || '';
1720 tableName += this.tableName || parseName(this.getModelName());
1730 this.trueTableName = tableName.toLowerCase();
174 }
1750 tableName = (this.dbName ? this.dbName + '.' : '') + this.trueTableName;
1760 return tableName;
177 },
178 /**
179 * 获取数据表信息
180 * @access protected
181 * @return Promise
182 */
183 getTableFields: function(table, all){
1840 this.initDb();
1850 if (table === true) {
1860 table = undefined;
1870 all = true;
188 }
1890 if (!isEmpty(this.fields)) {
1900 return getPromise(all ? this.fields : this.fields._field);
191 }
1920 var tableName = table || this.getTableName();
1930 var fields = tableFields[tableName];
1940 if (!isEmpty(fields)) {
1950 this.fields = fields;
1960 return getPromise(all ? fields : fields._field);
197 }
1980 var self = this;
199 //从数据表里查询字段信息
2000 return this.flushFields().then(function(fields){
2010 self.fields = fields;
2020 if (C('db_fields_cache')) {
2030 tableFields[tableName] = fields;
204 }
2050 return getPromise(all ? fields : fields._field);
206 });
207 },
208 /**
209 * 获取数据表信息
210 * @param {[type]} table [description]
211 * @return Promise [description]
212 */
213 flushFields: function(table){
2140 table = table || this.getTableName();
2150 return this.initDb().getFields(table).then(function(data){
2160 var fields = {
217 '_field': Object.keys(data || {}),
218 '_autoinc': false,
219 '_unique': []
220 };
2210 var types = {};
2220 for(var key in data){
2230 var val = data[key];
2240 types[key] = val.type;
2250 if (val.primary) {
2260 fields._pk = key;
2270 if (val.autoinc) {
2280 fields._autoinc = true;
229 }
2300 }else if (val.unique) {
2310 fields._unique.push(key);
232 }
233 }
2340 fields._type = types;
2350 return fields;
236 })
237 },
238 /**
239 * 获取类型为唯一的字段
240 * @return {[type]} [description]
241 */
242 getUniqueField: function(data){
2430 var unqiueFileds = this.fields._unique;
2440 var unqiue = '';
2450 unqiueFileds.some(function(item){
2460 if (!data || data[item]) {
2470 unqiue = item;
2480 return unqiue;
249 }
250 });
2510 return unqiue;
252 },
253 /**
254 * 获取上一次操作的sql
255 * @return {[type]} [description]
256 */
257 getLastSql: function(){
2580 return this.db.getLastSql();
259 },
260 /**
261 * 获取主键名称
262 * @access public
263 * @return string
264 */
265 getPk: function(){
2660 return this.fields._pk || this.pk;
267 },
268 /**
269 * 缓存
270 * @param {[type]} key [description]
271 * @param {[type]} expire [description]
272 * @param {[type]} type [description]
273 * @return {[type]} [description]
274 */
275 cache: function(key, timeout){
2760 if (key === undefined) {
2770 return this;
278 }
2790 var options = this.getCacheOptions(key, timeout);
2800 this._options.cache = options;
2810 return this;
282 },
283 /**
284 * 获取缓存的选项
285 * @param {[type]} key [description]
286 * @param {[type]} timeout [description]
287 * @return {[type]} [description]
288 */
289 getCacheOptions: function(key, timeout, type){
2900 if (isObject(key)) {
2910 return key;
292 }
2930 if (isNumber(key)) {
2940 timeout = key;
2950 key = '';
296 }
2970 var cacheType = type === undefined ? C('db_cache_type') : type;
2980 var options = {
299 key: key,
300 timeout: timeout || C('db_cache_timeout'),
301 type: cacheType,
302 gcType: 'dbCache'
303 }
3040 if (cacheType === 'File') {
3050 options.cache_path = C('db_cache_path');
306 }else{
3070 options.cacheData = dbCacheData;
308 }
3090 return options;
310 },
311 /**
312 * 指定查询数量
313 * @param {[type]} offset [description]
314 * @param {[type]} length [description]
315 * @return {[type]} [description]
316 */
317 limit: function(offset, length){
3180 this._options.limit = length === undefined ? offset : offset + ',' + length;
3190 return this;
320 },
321 /**
322 * 指定分页
323 * @return {[type]} [description]
324 */
325 page: function(page, listRows){
3260 this._options.page = listRows === undefined ? page : page + ',' + listRows;
3270 return this;
328 },
329 /**
330 * where条件
331 * @return {[type]} [description]
332 */
333 where: function(where){
3340 if (isString(where)) {
3350 where = {_string: where};
336 }
3370 this._options.where = extend(this._options.where || {}, where);
3380 return this;
339 },
340 /**
341 * 要查询的字段
342 * @param {[type]} field [description]
343 * @param {[type]} reverse [description]
344 * @return {[type]} [description]
345 */
346 field: function(field, reverse){
3470 if (isArray(field)) {
3480 field = field.join(',');
3490 }else if (!field) {
3500 field = '*';
351 }
3520 this._options.field = field;
3530 this._options.fieldReverse = reverse;
3540 return this;
355 },
356 /**
357 * 联合查询
358 * @return {[type]} [description]
359 */
360 union: function(union){
3610 if (!this._options.union) {
3620 this._options.union = [];
363 }
3640 this._options.union.push(union);
3650 return this;
366 },
367 /**
368 * 联合查询
369 * @param {[type]} join [description]
370 * @return {[type]} [description]
371 */
372 join: function(join){
3730 if (isArray(join)) {
3740 this._options.join = join;
375 }else{
3760 if (!this._options.join) {
3770 this._options.join = [];
378 }
3790 this._options.join.push(join);
380 }
3810 return this;
382 },
383 /**
384 * 生成查询SQL 可用于子查询
385 * @param {[type]} options [description]
386 * @return {[type]} [description]
387 */
388 buildSql: function(options){
3890 var self = this;
3900 return this.parseOptions(options).then(function(options){
3910 return '( ' + self.db.buildSelectSql(options) + ' )';
392 });
393 },
394 /**
395 * 解析参数
396 * @param {[type]} options [description]
397 * @return promise [description]
398 */
399 parseOptions: function(options, extraOptions){
4000 options = extend({}, this._options, this.parseWhereOptions(options), extraOptions);
401 // 查询过后清空sql表达式组装 避免影响下次查询
4020 this._options = {};
4030 options.table = options.table || this.getTableName();
4040 options.model = this.name;
4050 var promise = this.getTableFields(options.table);
406 //数据表别名
4070 if (options.alias) {
4080 options.table += ' ' + options.alias;
409 }
4100 var self = this;
4110 var keyReg = /[\.\|\&]/;
4120 return promise.then(function(fields){
413 // 字段类型验证
4140 if (isObject(options.where) && !isEmpty(fields)) {
415 // 对数组查询条件进行字段类型检查
4160 for(var key in options.where){
4170 var val = options.where[key];
4180 key = key.trim();
4190 if (fields.indexOf(key) > -1) {
4200 if (isScalar(val)) {
4210 options.where = self.parseType(options.where, key);
422 }
4230 }else if(key.substr(0, 1) !== '_' && !keyReg.test(key)){
4240 delete options.where[key];
425 }
426 }
427 }
428 //field反选
4290 if (options.field && options.fieldReverse) {
4300 var optionsField = options.field.split(',');
4310 options.field = fields.filter(function(item){
4320 if (optionsField.indexOf(item) > -1) {
4330 return;
434 }
4350 return item;
436 }).join(',');
437 }
4380 return self._optionsFilter(options, fields);
439 });
440 },
441 /**
442 * 选项过滤器
443 * 具体的Model类里进行实现
444 * @param {[type]} options [description]
445 * @return {[type]} [description]
446 */
447 _optionsFilter: function(options){
4480 return options;
449 },
450 /**
451 * 数据类型检测
452 * @param {[type]} data [description]
453 * @param {[type]} key [description]
454 * @return {[type]} [description]
455 */
456 parseType: function(data, key){
4570 var fieldType = this.fields._type[key] || '';
4580 if (fieldType.indexOf('bigint') === -1 && fieldType.indexOf('int') > -1) {
4590 data[key] = parseInt(data[key], 10) || 0;
4600 }else if(fieldType.indexOf('double') > -1 || fieldType.indexOf('float') > -1){
4610 data[key] = parseFloat(data[key]) || 0.0;
4620 }else if(fieldType.indexOf('bool') > -1){
4630 data[key] = !! data[key];
464 }
4650 return data;
466 },
467 /**
468 * 对插入到数据库中的数据进行处理,要在parseOptions后执行
469 * @param {[type]} data [description]
470 * @return {[type]} [description]
471 */
472 parseData: function(data){
4730 data = extend({}, data);
4740 var key;
4750 if (!isEmpty(this.fields)) {
4760 for(key in data){
4770 var val = data[key];
4780 if (this.fields._field.indexOf(key) === -1) {
4790 delete data[key];
4800 }else if(isScalar(val)){
4810 data = this.parseType(data, key);
482 }
483 }
484 }
485 //安全过滤
4860 if (typeof this._options.filter === 'function') {
4870 for(key in data){
4880 data[key] = this._options.filter.call(this, key, data[key]);
489 }
4900 delete this._options.filter;
491 }
4920 data = this._dataFilter(data);
4930 return data;
494 },
495 /**
496 * 数据过滤器
497 * 具体的Model类里进行实现
498 * @param {[type]} data [description]
499 * @return {[type]} [description]
500 */
501 _dataFilter: function(data){
5020 return data;
503 },
504 /**
505 * 数据插入之前操作,可以返回一个promise
506 * @param {[type]} data [description]
507 * @param {[type]} options [description]
508 * @return {[type]} [description]
509 */
510 _beforeAdd: function(data){
5110 return data;
512 },
513 /**
514 * 数据插入之后操作,可以返回一个promise
515 * @param {[type]} data [description]
516 * @param {[type]} options [description]
517 * @return {[type]} [description]
518 */
519 _afterAdd: function(data){
5200 return data;
521 },
522 /**
523 * 添加一条数据
524 * @param {[type]} data [description]
525 * @param {[type]} options [description]
526 * @param int 返回插入的id
527 */
528 add: function(data, options, replace){
529 //copy data
5300 data = extend({}, data);
5310 if (isEmpty(data)) {
5320 if (this._data) {
5330 data = this._data;
5340 this._data = {};
535 }else{
5360 return getPromise(L('_DATA_TYPE_INVALID_'), true);
537 }
538 }
5390 var self = this;
540 //解析后的选项
5410 var parsedOptions = {};
542 //解析后的数据
5430 var parsedData = {};
5440 return this.parseOptions(options).then(function(options){
5450 parsedOptions = options;
5460 return self._beforeAdd(data, parsedOptions);
547 }).then(function(data){
5480 parsedData = data;
5490 data = self.parseData(data);
5500 return self.db.insert(data, parsedOptions, replace);
551 }).then(function(){
5520 parsedData[self.getPk()] = self.db.getLastInsertId();
5530 return self._afterAdd(parsedData, parsedOptions);
554 }).then(function(){
5550 return parsedData[self.getPk()];
556 });
557 },
558 /**
559 * 如果当前条件的数据不存在,才添加
560 * @param {[type]} data 要插入的数据
561 * @param {[type]} where where条件
562 * @param boolean returnType 返回值是否包含type
563 * @return {[type]} promise
564 */
565 thenAdd: function(data, where, returnType){
5660 this.where(where);
5670 var self = this;
5680 return this.find().then(function(findData){
5690 if (!isEmpty(findData)) {
5700 var idValue = findData[self.getPk()];
5710 return returnType ? getObject([self.getPk(), 'type'], [idValue, 'exist']) : idValue;
572 }
5730 return self.add(data).then(function(insertId){
5740 return returnType ? getObject([self.getPk(), 'type'], [insertId, 'add']) : insertId;
575 });
576 });
577 },
578 /**
579 * 插入多条数据
580 * @param {[type]} data [description]
581 * @param {[type]} options [description]
582 * @param {[type]} replace [description]
583 */
584 addAll: function(data, options, replace){
5850 if (!isArray(data) || !isObject(data[0])) {
5860 return getPromise(L('_DATA_TYPE_INVALID_'), true);
587 }
5880 var self = this;
5890 return this.parseOptions(options).then(function(options){
5900 return self.db.insertAll(data, options, replace);
591 }).then(function(){
5920 return self.db.getLastInsertId();
593 });
594 },
595 /**
596 * 删除后续操作
597 * @return {[type]} [description]
598 */
599 _afterDelete: function(data){
6000 return data;
601 },
602 /**
603 * 删除数据
604 * @return {[type]} [description]
605 */
606 delete: function(options){
6070 var self = this;
6080 var parsedOptions = {};
6090 var affectedRows = 0;
6100 return this.parseOptions(options).then(function(options){
6110 parsedOptions = options;
6120 return self.db.delete(options);
613 }).then(function(rows){
6140 affectedRows = rows;
6150 return self._afterDelete(parsedOptions.where || {}, parsedOptions);
616 }).then(function(){
6170 return affectedRows;
618 })
619 },
620 /**
621 * 更新前置操作
622 * @param {[type]} data [description]
623 * @param {[type]} options [description]
624 * @return {[type]} [description]
625 */
626 _beforeUpdate: function(data){
6270 return data;
628 },
629 /**
630 * 更新后置操作
631 * @param {[type]} data [description]
632 * @param {[type]} options [description]
633 * @return {[type]} [description]
634 */
635 _afterUpdate: function(data){
6360 return data;
637 },
638 /**
639 * 更新数据
640 * @return {[type]} [description]
641 */
642 update: function(data, options){
6430 data = extend({}, data);
6440 if (isEmpty(data)) {
6450 if (this._data) {
6460 data = this._data;
6470 this._data = {};
648 }else{
6490 return getPromise(L('_DATA_TYPE_INVALID_'), true);
650 }
651 }
6520 var self = this;
6530 var pk = self.getPk();
6540 var parsedOptions = {};
6550 var parsedData = {};
6560 var affectedRows = 0;
6570 return this.parseOptions(options).then(function(options){
6580 parsedOptions = options;
6590 return self._beforeUpdate(data, options);
660 }).then(function(data){
6610 parsedData = data;
6620 data = self.parseData(data);
6630 if (isEmpty(parsedOptions.where)) {
664 // 如果存在主键数据 则自动作为更新条件
6650 if (!isEmpty(data[pk])) {
6660 parsedOptions.where = getObject(pk, data[pk]);
6670 delete data[pk];
668 }else{
6690 return getPromise(L('_OPERATION_WRONG_'), true);
670 }
671 }else{
6720 parsedData[pk] = parsedOptions.where[pk];
673 }
6740 return self.db.update(data, parsedOptions);
675 }).then(function(rows){
6760 affectedRows = rows;
6770 return self._afterUpdate(parsedData, parsedOptions);
678 }).then(function(){
6790 return affectedRows;
680 });
681 },
682 /**
683 * 更新多个数据,自动用主键作为查询条件
684 * @param {[type]} dataList [description]
685 * @return {[type]} [description]
686 */
687 updateAll: function(dataList){
6880 if (!isArray(dataList) || !isObject(dataList[0])) {
6890 return getPromise(L('_DATA_TYPE_INVALID_'), true);
690 }
6910 var self = this;
6920 var promises = dataList.map(function(data){
6930 return self.update(data);
694 });
6950 return Promise.all(promises);
696 },
697 /**
698 * 更新某个字段的值
699 * @param {[type]} field [description]
700 * @param {[type]} value [description]
701 * @return {[type]} [description]
702 */
703 updateField: function(field, value){
7040 var data = {};
7050 if (isObject(field)) {
7060 data = field;
707 }else{
7080 data[field] = value;
709 }
7100 return this.update(data);
711 },
712 /**
713 * 字段值增长
714 * @return {[type]} [description]
715 */
716 updateInc: function(field, step){
7170 step = parseInt(step, 10) || 1;
7180 return this.updateField(field, ['exp', field + '+' + step]);
719 },
720 /**
721 * 字段值减少
722 * @return {[type]} [description]
723 */
724 updateDec: function(field, step){
7250 step = parseInt(step, 10) || 1;
7260 return this.updateField(field, ['exp', field + '-' + step]);
727 },
728 /**
729 * 解析options中简洁的where条件
730 * @return {[type]} [description]
731 */
732 parseWhereOptions: function(options){
7330 if (isNumber(options) || isString(options)) {
7340 var pk = this.getPk();
7350 options += '';
7360 var where = {};
7370 if (options.indexOf(',') > -1) {
7380 where[pk] = ['IN', options];
739 }else{
7400 where[pk] = options;
741 }
7420 options = {
743 where: where
744 };
745 }
7460 return options || {};
747 },
748 /**
749 * find查询后置操作
750 * @return {[type]} [description]
751 */
752 _afterFind: function(result){
7530 return result;
754 },
755 /**
756 * 查询一条数据
757 * @return 返回一个promise
758 */
759 find: function(options){
7600 var self = this;
7610 var parsedOptions = {};
7620 return this.parseOptions(options, {
763 limit: 1
764 }).then(function(options){
7650 parsedOptions = options;
7660 return self.db.select(options);
767 }).then(function(data){
7680 return self._afterFind(data[0] || {}, parsedOptions);
769 });
770 },
771 /**
772 * 查询后置操作
773 * @param {[type]} result [description]
774 * @param {[type]} options [description]
775 * @return {[type]} [description]
776 */
777 _afterSelect: function(result){
7780 return result;
779 },
780 /**
781 * 查询数据
782 * @return 返回一个promise
783 */
784 select: function(options){
7850 var self = this;
7860 var parsedOptions = {};
7870 return this.parseOptions(options).then(function(options){
7880 parsedOptions = options;
7890 return self.db.select(options);
790 }).then(function(result){
7910 return self._afterSelect(result, parsedOptions);
792 });
793 },
794 selectAdd: function(fields, table, options){
7950 var self = this;
7960 return this.parseOptions(options).then(function(options){
7970 fields = fields || options.field;
7980 table = table || self.getTableName();
7990 return self.db.selectInsert(fields, table, options);
800 });
801 },
802 /**
803 * 返回数据里含有count信息的查询
804 * @param options 查询选项
805 * @param pageFlag 当页面不合法时的处理方式,true为获取第一页,false为获取最后一页,undefined获取为空
806 * @return promise
807 */
808 countSelect: function(options, pageFlag){
8090 if (isBoolean(options)) {
8100 pageFlag = options;
8110 options = {};
812 }
8130 var self = this;
814 //解析后的options
8150 var parsedOptions = {};
8160 var result = {};
8170 return this.parseOptions(options).then(function(options){
8180 delete options.table;
8190 parsedOptions = options;
8200 return self.options({
821 where: options.where,
822 cache: options.cache,
823 join: options.join
824 }).count(self.getTableName() + '.' + self.getPk());
825 }).then(function(count){
8260 var pageOptions = parsePage(parsedOptions);
8270 var totalPage = Math.ceil(count / pageOptions.num);
8280 if (isBoolean(pageFlag)) {
8290 if (pageOptions.page > totalPage) {
8300 pageOptions.page = pageFlag === true ? 1 : totalPage;
831 }
8320 parsedOptions.page = pageOptions.page + ',' + pageOptions.num;
833 }
8340 result = extend({count: count, total: totalPage}, pageOptions);
8350 return self.select(parsedOptions);
836 }).then(function(data){
8370 result.data = data;
8380 return result;
839 });
840 },
841 /**
842 * 获取一条记录的某个字段值
843 * @return {[type]} [description]
844 */
845 getField: function(field, sepa){
8460 field = field.trim();
8470 var self = this;
8480 var multi = false;
8490 var parseOptions;
8500 return this.parseOptions({
851 'field': field
852 }).then(function(options){
8530 parseOptions = options;
8540 if (field.indexOf(',') > -1) {
8550 if (options.limit === undefined && isNumber(sepa)) {
8560 options.limit = sepa;
857 }
8580 multi = true;
859 }else{
8600 options.limit = isNumber(sepa) ? sepa : 1;
861 }
8620 return self.db.select(options);
863 }).then(function(data){
8640 if (multi) {
8650 var length = field.split(',').length;
8660 field = Object.keys(data[0] || {});
8670 var key = field.shift();
8680 var key2 = field.shift();
8690 var cols = {};
8700 data.forEach(function(item){
8710 var name = item[key];
8720 if (length === 2) {
8730 cols[name] = item[key2];
874 }else{
8750 cols[name] = isString(sepa) ? item.join(sepa) : item;
876 }
877 });
8780 return cols;
879 }else{
8800 if (sepa !== true && parseOptions.limit === 1) {
8810 return data[0];
882 }
8830 return Object.values(data[0] || {})[0];
884 }
885 });
886 },
887 /**
888 * 根据某个字段值获取一条数据
889 * @param {[type]} name [description]
890 * @param {[type]} value [description]
891 * @return {[type]} [description]
892 */
893 getBy: function(name, value){
8940 var where = getObject(name, value);
8950 return this.where(where).find();
896 },
897 /**
898 * SQL查询
899 * @return {[type]} [description]
900 */
901 query: function(sql, parse){
9020 if (parse !== undefined && !isBoolean(parse) && !isArray(parse)) {
9030 parse = [].slice.call(arguments);
9040 parse.shift();
905 }
9060 var self = this;
9070 return this.parseSql(sql, parse).then(function(sql){
9080 return self.db.query(sql);
909 });
910 },
911 /**
912 * 执行SQL语法,非查询类的SQL语句,返回值为影响的行数
913 * @param {[type]} sql [description]
914 * @param {[type]} parse [description]
915 * @return {[type]} [description]
916 */
917 execute: function(sql, parse){
9180 if (parse !== undefined && !isBoolean(parse) && !isArray(parse)) {
9190 parse = [].slice.call(arguments);
9200 parse.shift();
921 }
9220 var self = this;
9230 return this.parseSql(sql, parse).then(function(sql){
9240 return self.db.execute(sql);
925 });
926 },
927 /**
928 * 解析SQL语句
929 * @return promise [description]
930 */
931 parseSql: function(sql, parse){
9320 var promise = null;
9330 var self = this;
9340 if (parse === true) {
9350 promise = this.parseOptions().then(function(options){
9360 return self.db.parseSql(options);
937 });
938 }else{
9390 if (parse === undefined) {
9400 parse = [];
941 }else{
9420 parse = isArray(parse) ? parse : [parse];
943 }
9440 parse.unshift(sql);
9450 sql = util.format.apply(null, parse);
9460 var map = {
947 '__TABLE__': '`' + this.getTableName() + '`'
948 };
9490 sql = sql.replace(/__([A-Z]+)__/g, function(a, b){
9500 return map[a] || ('`' + C('db_prefix') + b.toLowerCase() + '`');
951 });
9520 promise = getPromise(sql);
953 }
9540 this.initDb().setModel(self.name);
9550 return promise;
956 },
957 /**
958 * 设置数据对象值
959 * @return {[type]} [description]
960 */
961 data: function(data){
9620 if (data === true) {
9630 return this._data;
964 }
9650 if (isString(data)) {
9660 data = querystring.parse(data);
967 }
9680 this._data = data;
9690 return this;
970 },
971 /**
972 * 设置操作选项
973 * @param {[type]} options [description]
974 * @return {[type]} [description]
975 */
976 options: function(options){
9770 if (options === true) {
9780 return this._options;
979 }
9800 this._options = options;
9810 return this;
982 },
983 /**
984 * 关闭数据库连接
985 * @return {[type]} [description]
986 */
987 close: function(){
9880 delete dbInstances[this.configKey];
9890 if (this.db) {
9900 this.db.close();
991 }
992 }
993 };
994}).extend(function(){
9951 'use strict';
996 //追加的方法
9971 var methods = {};
998 // 链操作方法列表
9991 var methodNameList = [
1000 'table','order','alias','having','group',
1001 'lock','auto','filter','validate'
1002 ];
10031 methodNameList.forEach(function(item){
10049 methods[item] = function(data){
10050 this._options[item] = data;
10060 return this;
1007 };
1008 });
10091 methods.distinct = function(data){
10100 this._options.distinct = data;
1011 //如果传过来一个字段,则映射到field上
10120 if (isString(data)) {
10130 this._options.field = data;
1014 }
10150 return this;
1016 };
10171 ['count','sum','min','max','avg'].forEach(function(item){
10185 methods[item] = function(data){
10190 var field = data || '*';
10200 return this.getField(item.toUpperCase() + '(' + field + ') AS thinkjs_' + item, true);
1021 };
1022 });
1023 //方法别名
10241 var aliasMethodMap = {
1025 update: 'save',
1026 updateField: 'setField',
1027 updateInc: 'setInc',
1028 updateDec: 'setDec'
1029 };
10301 Object.keys(aliasMethodMap).forEach(function(key){
10314 var value = aliasMethodMap[key];
10324 methods[value] = function(){
10330 return this[key].apply(this, arguments);
1034 };
1035 });
10361 return methods;
1037});
1038/**
1039 * 关闭所有的数据库连接
1040 * @return {[type]} [description]
1041 */
10421Model.close = global.closeDb = function(){
10430 'use strict';
10440 for(var key in dbInstances) {
10450 dbInstances[key].close();
1046 }
1047
10480 dbInstances = {};
1049};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Think.js

56%
147
83
64
LineHitsSource
11var fs = require('fs');
21var cluster = require('cluster');
3
4//自动加载进行识别的路径
51var autoloadPaths = {};
6/**
7 * [exports description]
8 * @type {Object}
9 */
101module.exports = {
11 /**
12 * [start description]
13 * @return {[type]} [description]
14 */
15 start: function(){
161 'use strict';
171 this.init();
181 this.processEvent();
19 //加载文件
201 this.loadFiles();
21 //合并自动加载的路径
221 this.mergeAutoloadPath();
23 //thinkRequire的autoload
241 registerAutoload(this.autoload);
25 //debug模式
261 if (APP_DEBUG) {
270 this.debug();
28 }
29 //记录进程的id
301 this.logPid();
31
321 thinkRequire('App').run();
33 },
34 /**
35 * 定义一些目录,加载框架的基础文件
36 * @return {[type]} [description]
37 */
38 init: function(){
391 'use strict';
40 //系统路径设置
411 global.THINK_LIB_PATH = THINK_PATH + '/Lib';
421 global.THINK_EXTEND_PATH = THINK_LIB_PATH + '/Extend';
43 //应用路径设置
441 var config = {
45 COMMON_PATH: APP_PATH + '/Common',
46 LIB_PATH: APP_PATH + '/Lib',
47 CONF_PATH: APP_PATH + '/Conf',
48 LANG_PATH: APP_PATH + '/Lang',
49 VIEW_PATH: APP_PATH + '/View',
50 //HTML_PATH: RUNTIME_PATH + '/Html',
51 LOG_PATH: RUNTIME_PATH + '/Log',
52 TEMP_PATH: RUNTIME_PATH + '/Temp',
53 DATA_PATH: RUNTIME_PATH + '/Data',
54 CACHE_PATH: RUNTIME_PATH + '/Cache'
55 };
561 for (var name in config) {
579 if (global[name] === undefined) {
589 global[name] = config[name];
59 }
60 }
611 require(THINK_PATH + '/Common/extend.js');
621 require(THINK_PATH + '/Common/common.js');
631 require(THINK_PATH + '/Common/function.js');
64 //别名导入
651 aliasImport(require(THINK_PATH + '/Conf/alias.js'));
66 },
67 /**
68 * 注册异常处理
69 * @return {[type]} [description]
70 */
71 processEvent: function(){
721 'use strict';
731 process.on('uncaughtException', function(err) {
740 console.log(isError(err) ? err.stack : err);
75 });
76 },
77 /**
78 * 加载项目下对应的文件
79 * @return {[type]} [description]
80 */
81 loadFiles: function(){
821 'use strict';
831 C(null); //移除之前的所有配置
84 //加载系统默认配置
851 C(require(THINK_PATH + '/Conf/config.js'));
86 //加载用户配置
871 var file = CONF_PATH + '/config.js';
881 if (isFile(file)) {
891 C(require(file));
90 }
91 //加载模式的配置文件
921 if (APP_MODE) {
931 var modeFiles = [
94 THINK_PATH + '/Conf/mode.js',
95 CONF_PATH + '/mode.js'
96 ];
971 modeFiles.forEach(function(file){
982 if (isFile(file)) {
991 var conf = require(file);
1001 if (conf[APP_MODE]) {
1011 C(conf[APP_MODE]);
102 }
103 }
104 });
105 }
106 //自定义路由
1071 if (C('url_route_on') && isFile(CONF_PATH + '/route.js')) {
1080 C('url_route_rules', require(CONF_PATH + '/route.js'));
109 }
110 //加载行为配置
1111 if (C('app_tag_on')) {
112 //加载系统行为配置
1131 C('sys_tag', require(THINK_PATH + '/Conf/tag.js'));
114 //加载用户的行为配置
1151 var tagFile = CONF_PATH + '/tag.js';
1161 if (isFile(tagFile)) {
1170 C('tag', require(tagFile));
118 }
119 }
120 //common文件
1211 if (isFile(COMMON_PATH + '/common.js')) {
1221 require(COMMON_PATH + '/common.js');
123 }
124 //别名文件
1251 if (isFile(COMMON_PATH + '/alias.js')) {
1260 aliasImport(require(COMMON_PATH + '/alias.js'));
127 }
1281 this.loadExtConfig();
1291 this.loadExtFiles();
130 },
131 //加载自定义外部文件
132 loadExtFiles: function(){
1331 'use strict';
1341 var files = C('load_ext_file');
1351 if (files) {
1361 if (isString(files)) {
1370 files = files.split(',');
138 }
1391 files.forEach(function(file){
1400 file = COMMON_PATH + '/' + file + '.js';
1410 if (isFile(file)) {
1420 require(file);
143 }
144 });
145 }
146 },
147 //加载额外的配置
148 loadExtConfig: function(){
1491 'use strict';
1501 var files = C('load_ext_config');
1511 if (files) {
1521 if (isString(files)) {
1530 files = files.split(',');
154 }
1551 files.forEach(function(file){
1560 file = CONF_PATH + '/' + file + '.js';
1570 if (isFile(file)) {
1580 C(require(file));
159 }
160 });
161 }
162 },
163 //加载debug模式配置文件
164 loadDebugFiles: function(){
1650 'use strict';
166 //加载debug模式下的配置
1670 C(require(THINK_PATH + '/Conf/debug.js'));
168 //debug下自定义状态的配置
1690 var status = C('app_status');
1700 if (status) {
1710 if (isFile(CONF_PATH + '/' + status + '.js')) {
1720 C(require(CONF_PATH + '/' + status + '.js'));
173 }
174 }else{
1750 if (isFile(CONF_PATH + '/debug.js')) {
1760 C(require(CONF_PATH + '/debug.js'));
177 }
178 }
1790 if (APP_MODE) {
1800 var modeFiles = [
181 THINK_PATH + '/Conf/mode.js',
182 CONF_PATH + '/mode.js'
183 ];
1840 modeFiles.forEach(function(file){
1850 if (isFile(file)) {
1860 var conf = require(file);
1870 var key = APP_MODE + '_debug';
1880 if (conf[key]) {
1890 C(conf[key]);
190 }
191 }
192 });
193 }
194 },
195 /**
196 * debug模式下一些特殊处理
197 * @return {[type]} [description]
198 */
199 debug: function(){
2000 'use strict';
2010 this.loadDebugFiles();
202 //清除require的缓存
2030 if (C('clear_require_cache')) {
204 //这些文件不清除缓存
2050 var retainFiles = C('debug_retain_files');
2060 var self = this;
2070 setInterval(function(){
2080 var fn = function(item){
209 //windows目录定界符为\
2100 if (process.platform === 'win32') {
2110 item = item.replace(/\//g, '\\');
212 }
2130 if (file.indexOf(item) > -1) {
2140 return true;
215 }
216 };
2170 for(var file in require.cache){
2180 var flag = retainFiles.some(fn);
2190 if (!flag) {
2200 delete require.cache[file];
221 }
222 }
2230 self.loadFiles();
2240 self.loadDebugFiles();
225 }, 100);
226 }
227 },
228 /**
229 * 记录当前进程的id
230 * 记录在Runtime/Data/app.pid文件里
231 * @return {[type]} [description]
232 */
233 logPid: function(){
2341 'use strict';
2351 if (C('log_process_pid') && cluster.isMaster) {
2360 mkdir(DATA_PATH);
2370 var pidFile = DATA_PATH + '/app.pid';
2380 fs.writeFileSync(pidFile, process.pid);
2390 chmod(pidFile);
240 //进程退出时删除该文件
2410 process.on('SIGTERM', function () {
2420 if (fs.existsSync(pidFile)) {
2430 fs.unlinkSync(pidFile);
244 }
2450 process.exit(0);
246 });
247 }
248 },
249 /**
250 * 合并autoload的path
251 * @return {[type]} [description]
252 */
253 mergeAutoloadPath: function(){
2541 'use strict';
2551 var file = '__CLASS__.js';
2561 var sysAutoloadPath = {
257 'Behavior': [
258 LIB_PATH + '/Behavior/' + file,
259 THINK_LIB_PATH + '/Behavior/' + file
260 ],
261 'Model': [
262 LIB_PATH + '/Model/' + file,
263 THINK_EXTEND_PATH + '/Model/' + file
264 ],
265 'Controller': [
266 LIB_PATH + '/Controller/' + file,
267 THINK_EXTEND_PATH + '/Controller/' + file
268 ],
269 'Cache': [
270 LIB_PATH + '/Driver/Cache/' + file,
271 THINK_LIB_PATH + '/Driver/Cache/' + file
272 ],
273 'Db': [
274 LIB_PATH + '/Driver/Db/' + file,
275 THINK_LIB_PATH + '/Driver/Db/' + file
276 ],
277 'Template': [
278 LIB_PATH + '/Driver/Template/' + file,
279 THINK_LIB_PATH + '/Driver/Template/' + file
280 ],
281 'Socket': [
282 LIB_PATH + '/Driver/Socket/' + file,
283 THINK_LIB_PATH + '/Driver/Socket/' + file
284 ],
285 'Session': [
286 LIB_PATH + '/Driver/Session/' + file,
287 THINK_LIB_PATH + '/Driver/Session/' + file
288 ]
289 };
2901 var autoloadPath = C('autoload_path');
2911 for(var type in autoloadPath){
2920 var paths = autoloadPath[type];
2930 var override = false;
2940 if (!isArray(paths)) {
2950 paths = [paths];
2960 }else if (isBoolean(paths[0])) {
2970 override = paths.shift();
298 }
2990 if (override) {
3000 sysAutoloadPath[type] = paths;
301 }else{
3020 paths.push.apply(paths, sysAutoloadPath[type]);
3030 sysAutoloadPath[type] = paths;
304 }
305 }
3061 autoloadPaths = sysAutoloadPath;
307 },
308 //thinkRequire的自动加载
309 autoload: function(cls){
31019 'use strict';
31119 var filepath = '';
31219 var fn = function(item){
31335 item = item.replace(/__CLASS__/g, cls);
31435 if (isFile(item)) {
31518 filepath = item;
31618 return true;
317 }
318 };
31919 for(var name in autoloadPaths){
32072 var length = name.length;
32172 if (cls.substr(0 - length) === name) {
32218 var list = autoloadPaths[name];
32318 list.some(fn);
32418 if (filepath) {
32518 if (!APP_DEBUG) {
32618 aliasImport(cls, filepath);
327 }
32818 return filepath;
329 }
330 }
331 }
332 }
333};
334

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/View.js

76%
42
32
10
LineHitsSource
1/**
2 * view
3 * @return {[type]} [description]
4 */
51module.exports = Class(function(){
61 'use strict';
71 return {
8 tVar: {},
9 init: function(http){
101 this.http = http;
11 },
12 /**
13 * 给变量赋值
14 * @param {[type]} name [description]
15 * @param {[type]} value [description]
16 * @return {[type]} [description]
17 */
18 assign: function(name, value){
192 if (name === undefined) {
200 return this.tVar;
21 }
222 if (isString(name) && arguments.length === 1) {
230 return this.tVar[name];
24 }
252 if (isObject(name)) {
260 this.tVar = extend(this.tVar, name);
27 }else{
282 this.tVar[name] = value;
29 }
30 },
31 /**
32 * 获取变量的值
33 * @param {[type]} name [description]
34 * @return {[type]} [description]
35 */
36 get: function(name){
370 if (!name) {
380 return this.tVar;
39 }
400 return this.tVar[name];
41 },
42 /**
43 * 输出模版文件内容
44 * @param {[type]} templateFile [description]
45 * @param {[type]} charset [description]
46 * @param {[type]} contentType [description]
47 * @param {[type]} content [description]
48 * @return {[type]} [description]
49 */
50 display: function(templateFile, charset, contentType, content){
511 var self = this;
521 return tag('view_init', this.http).then(function(){
531 return self.fetch(templateFile, content);
54 }).then(function(content){
551 self.render(content, charset, contentType);
561 return tag('view_end', self.http, content);
57 }).then(function(){
581 return self.http.end();
59 }).catch(function(){
600 return self.http.end();
61 });
62 },
63 /**
64 * 渲染模版
65 * @param {[type]} content [description]
66 * @param {[type]} charset [description]
67 * @param {[type]} contentType [description]
68 * @return {[type]} [description]
69 */
70 render: function(content, charset, contentType){
711 if (!this.http.cthIsSend) {
721 if (charset === undefined) {
731 charset = C('encoding');
74 }
751 if (contentType === undefined) {
761 contentType = C('tpl_content_type');
77 }
781 this.http.setHeader('Content-Type', contentType + '; charset=' + charset);
79 }
801 if (C('show_exec_time')) {
810 this.http.sendTime('Exec-Time');
82 }
831 this.http.echo(content || '', C('encoding'));
84 },
85 /**
86 * 获取模版文件内容
87 * @param {[type]} templateFile [description]
88 * @param {[type]} content [description]
89 * @return {[type]} [description]
90 */
91 fetch: function(templateFile, content){
921 var self = this;
931 var promise = getPromise('');
941 if (content === undefined) {
951 promise = tag('view_template', this.http, templateFile).then(function(file){
961 if (file && isFile(file)) {
971 templateFile = file;
98 }
99 });
100 }
1011 return promise.then(function(){
1021 if (!templateFile) {
1030 return '';
104 }
1051 return tag('view_parse', self.http, {
106 'var': self.tVar,
107 'file': templateFile,
108 'content': content
109 }).then(function(content){
1101 return tag('view_filter', self.http, content);
111 });
112 }).catch(function(err){
113 //输出模版解析异常
1140 console.log(isError(err) ? err.stack : err);
115 });
116 }
117 };
118});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Cache/FileCache.js

5%
67
4
63
LineHitsSource
11var fs = require('fs');
2/**
3 * 基于文件的缓存
4 * @return {[type]} [description]
5 */
61module.exports = Cache(function(){
71 'use strict';
81 return {
9 gcType: 'FileCache',
10 init: function(options){
110 this.options = extend({
12 cache_path: C('cache_path'), //缓存目录
13 cache_path_level: 2, //缓存子目录深度
14 cache_file_suffix: C('cache_file_suffix') //缓存文件后缀名
15 }, options);
160 mkdir(this.options.cache_path);
170 this.gcType += ':' + this.options.cache_path;
18
190 this.super_('init', this.options);
20 },
21 /**
22 * 存储的缓存文件
23 * @param {[type]} name [description]
24 * @return {[type]} [description]
25 */
26 getStoredFile: function(name){
270 name = md5(this.key || name);
280 var dir = name.split('').slice(0, this.options.cache_path_level).join('/');
290 mkdir(this.options.cache_path + '/' + dir);
300 var path = this.options.cache_path + '/' + dir + '/' + name + this.options.cache_file_suffix;
310 return path;
32 },
33 /**
34 * 获取缓存,返回promise
35 * @param {[type]} name [description]
36 * @return {[type]} [description]
37 */
38 getData: function(name){
390 var filePath = this.getStoredFile(name);
400 if (!isFile(filePath)) {
410 return getPromise();
42 }
430 var deferred = getDefer();
440 fs.exists(filePath, function(exists){
450 if (!exists) {
460 return deferred.resolve();
47 }
480 fs.readFile(filePath, {encoding: 'utf8'}, function(error, content){
490 if (error || !content) {
500 return deferred.resolve();
51 }
520 try{
530 var data = JSON.parse(content);
540 if (Date.now() > data.expire) {
550 fs.unlink(filePath, function(){
560 return deferred.resolve();
57 });
58 }else{
590 deferred.resolve(data.data);
60 }
61 }catch(e){
62 //异常时删除该文件
630 fs.unlink(filePath, function(){
640 return deferred.resolve();
65 });
66 }
67 });
68 });
690 return deferred.promise;
70 },
71 get: function(name){
720 return this.getData().then(function(data){
730 return (data || {})[name];
74 })
75 },
76 setData: function(name, value, timeout){
770 if (isObject(name)) {
780 timeout = value;
79 }
800 if (timeout === undefined) {
810 timeout = this.options.timeout;
82 }
830 var filePath = this.getStoredFile(name);
840 var data = {
85 data: isObject(name) ? name : getObject(name, value),
86 expire: Date.now() + timeout * 1000,
87 timeout: timeout
88 };
890 var deferred = getDefer();
900 fs.writeFile(filePath, JSON.stringify(data), function(){
91 //修改缓存文件权限,避免不同账号下启动时可能会出现无权限的问题
920 chmod(filePath);
930 deferred.resolve();
94 })
950 return deferred.promise;
96 },
97 /**
98 * 设置缓存
99 * @param {[type]} name [description]
100 * @param {[type]} value [description]
101 * @param {[type]} expire [description]
102 */
103 set: function(name, value, timeout){
1040 return this.setData(name, value, timeout);
105 },
106 /**
107 * 删除缓存
108 * @param {[type]} name [description]
109 * @return {[type]} [description]
110 */
111 rm: function(name){
1120 var filePath = this.getStoredFile(name);
1130 if (isFile(filePath)) {
1140 var deferred = getDefer();
1150 fs.unlink(filePath, function(){
1160 deferred.resolve();
117 })
1180 return deferred.promise;
119 }
1200 return getPromise();
121 },
122 /**
123 * gc
124 * @param {[type]} now [description]
125 * @return {[type]} [description]
126 */
127 gc: function(now, path){
1280 path = path || this.options.cache_path;
1290 var self = this;
1300 var files = fs.readdirSync(path);
1310 files.forEach(function(item){
1320 var filePath = path + '/' + item;
1330 var stat = fs.statSync(filePath);
1340 if (stat.isDirectory()) {
1350 self.gc(now, filePath);
1360 }else if (stat.isFile()) {
1370 var data = getFileContent(filePath);
1380 try{
1390 data = JSON.parse(data);
1400 if (now > data.expire) {
1410 fs.unlink(filePath, function(){});
142 }
143 }catch(e){}
144 }
145 });
146 }
147 };
148});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Cache/MemcacheCache.js

35%
14
5
9
LineHitsSource
11var memcache = thinkRequire('MemcacheSocket');
21module.exports = Cache(function(){
31 'use strict';
41 var instance = null;
51 return {
6 namePrefix: '__thinkjs__',
7 init: function(options){
80 this.super_('init', options);
90 if (!instance) {
100 instance = memcache(C('memcache_port'), C('memcache_host'));
11 }
120 this.handle = instance;
13 },
14 get: function(name){
150 return this.handle.get(this.namePrefix + name).then(function(value){
160 return value ? JSON.parse(value) : value;
17 })
18 },
19 set: function(name, value, timeout){
200 timeout = timeout || this.options.timeout;
210 return this.handle.set(this.namePrefix + name, JSON.stringify(value), timeout);
22 },
23 rm: function(name){
240 return this.handle.delete(this.namePrefix + name);
25 }
26 };
27});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Db/MysqlDb.js

8%
61
5
56
LineHitsSource
1/**
2 * mysql数据库
3 * @return {[type]} [description]
4 */
51var mysqlSocket = thinkRequire('MysqlSocket');
61module.exports = Db(function(){
71 'use strict';
81 var keyReg = /[,\'\"\*\(\)`.\s]/;
91 return {
10 init: function(config){
110 this.super_('init');
120 if (config) {
130 this.config = config;
14 }
150 this.lastInsertId = 0;
16 //查询等待
170 this.queryWaiting = {};
18 },
19 /**
20 * 连接数据库
21 * @param {[type]} config [description]
22 * @param {[type]} linknum [description]
23 * @return {[type]} [description]
24 */
25 connect: function(config, linknum){
260 linknum = linknum || 0;
270 if (!this.linkIds[linknum]) {
280 config = config || this.config;
290 this.linkIds[linknum] = mysqlSocket(config);
300 this.connected = true;
31 }
320 return this.linkIds[linknum];
33 },
34 /**
35 * 查询一条sql
36 * @param string str
37 * @return promise
38 */
39 query: function(str){
400 this.initConnect(false);
410 if (!this.linkId) {
420 return getPromise('linkId is null', true);
43 }
440 this.queryStr = str;
450 var self = this;
460 if (!(str in this.queryWaiting)) {
470 this.queryWaiting[str] = [];
480 return this.linkId.query(str).then(function(data){
490 process.nextTick(function(){
500 self.queryWaiting[str].forEach(function(deferred){
510 deferred.resolve(data);
52 });
530 delete self.queryWaiting[str];
54 })
550 return data;
56 });
57 }else{
580 var deferred = getDefer();
590 this.queryWaiting[str].push(deferred);
600 return deferred.promise;
61 }
62 },
63 /**
64 * 执行一条sql, 返回影响的行数
65 * @param {[type]} str [description]
66 * @return {[type]} [description]
67 */
68 execute: function(str){
690 this.initConnect(false);
700 if (!this.linkId) {
710 return getPromise('linkId is null', true);
72 }
730 this.queryStr = str;
740 var self = this;
750 return this.linkId.query(str).then(function(data){
760 self.lastInsertId = data.insertId;
770 return data.affectedRows || 0;
78 });
79 },
80 /**
81 * 获取数据表字段信息
82 * @param string tableName 数据表名
83 * @return promise 返回一个promise
84 */
85 getFields: function(tableName){
860 var sql = 'SHOW COLUMNS FROM ' + this.parseKey(tableName);
870 return this.query(sql).then(function(data){
880 var ret = {};
890 data.forEach(function(item){
900 ret[item.Field] = {
91 'name': item.Field,
92 'type': item.Type,
93 'notnull': item.Null === '',
94 'default': item.Default,
95 'primary': item.Key === 'PRI',
96 'unique': item.Key === 'UNI',
97 'autoinc': item.Extra.toLowerCase() === 'auto_increment'
98 };
99 });
1000 return ret;
101 });
102 },
103 /**
104 * 获取数据库的表信息
105 * @param {[type]} dbName [description]
106 * @return {[type]} [description]
107 */
108 getTables: function(dbName){
1090 var sql = 'SHOW TABLES';
1100 if (dbName) {
1110 sql += ' FROM ' + dbName;
112 }
1130 return this.query(sql).then(function(data){
1140 return data.map(function(item){
1150 for(var key in item){
1160 return item[key];
117 }
118 });
119 });
120 },
121 /**
122 * 关闭连接
123 * @return {[type]} [description]
124 */
125 close: function(){
1260 if (this.linkId) {
1270 this.linkId.close();
1280 this.linkId = null;
129 }
130 },
131 /**
132 * 解析key
133 * @param {[type]} key [description]
134 * @return {[type]} [description]
135 */
136 parseKey: function(key){
1370 key = (key || '').trim();
1380 if (!keyReg.test(key)) {
1390 key = '`' + key + '`';
140 }
1410 return key;
142 },
143 /**
144 * 获取最后插入的id
145 * @return {[type]} [description]
146 */
147 getLastInsertId: function(){
1480 return this.lastInsertId;
149 }
150 };
151});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Session/DbSession.js

9%
33
3
30
LineHitsSource
1/**
2 * DbSession
3 * 需要在数据库中建立对应的数据表
4 *
5 * DROP TABLE IF EXISTS `think_session`;
6 CREATE TABLE `think_session` (
7 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
8 `key` varchar(255) NOT NULL DEFAULT '',
9 `data` text,
10 `expire` bigint(11) NOT NULL,
11 PRIMARY KEY (`id`),
12 UNIQUE KEY `cookie` (`key`),
13 KEY `expire` (`expire`)
14 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
15 *
16 *
17 * @return {[type]} [description]
18 */
191module.exports = Cache(function(){
201 'use strict';
211 return {
22 /**
23 * gc类型
24 * @type {String}
25 */
26 gcType: 'DbSession',
27 /**
28 * [init description]
29 * @param {[type]} options [description]
30 * @return {[type]} [description]
31 */
32 init: function(options){
330 this.super_('init', options);
340 this.key = this.options.cookie;
350 this.data = {};
360 this.initData();
37 },
38 /**
39 * 初始化数据
40 * @return {[type]} [description]
41 */
42 initData: function(){
430 if (!this.promise) {
440 var model = D('Session');
450 var self = this;
460 this.promise = model.where({key: this.key}).find().then(function(data){
470 self.data = {};
480 if (isEmpty(data)) {
490 return model.add({
50 key: self.key,
51 expire: Date.now() + self.options.timeout * 1000
52 });
53 }
540 if (Date.now() > data.expire) {
550 return;
56 }
570 self.data = JSON.parse(data.data || '{}');
58 });
59 }
600 return this.promise;
61 },
62 /**
63 * 获取
64 * @param {[type]} name [description]
65 * @return {[type]} [description]
66 */
67 get: function(name){
680 var self = this;
690 return this.initData().then(function(){
700 return self.data[name];
71 });
72 },
73 /**
74 * 设置
75 * @param {[type]} name [description]
76 * @param {[type]} value [description]
77 */
78 set: function(name, value){
790 var self = this;
800 return this.initData().then(function(){
810 self.data[name] = value;
82 });
83 },
84 /**
85 * 删除
86 * @param {[type]} name [description]
87 * @return {[type]} [description]
88 */
89 rm: function(name){
900 if (this.data) {
910 delete this.data[name];
92 }
930 return getPromise();
94 },
95 /**
96 * 将数据保存到数据库中
97 * @return {[type]} [description]
98 */
99 flush: function(){
1000 var model = D('Session');
1010 var self = this;
1020 var data = {
103 expire: Date.now() + self.options.timeout * 1000,
104 data: JSON.stringify(self.data)
105 };
1060 return this.initData().then(function(){
1070 return model.where({key: self.key}).update(data);
108 });
109 },
110 /**
111 * [gc description]
112 * @param {[type]} now [description]
113 * @return {[type]} [description]
114 */
115 gc: function(now){
1160 return D('Session').where({
117 expire: ['<', now]
118 }).delete();
119 }
120 };
121});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Session/FileSession.js

15%
26
4
22
LineHitsSource
1/**
2 * 文件Session
3 * @return {[type]} [description]
4 */
5
61var os = require('os');
71module.exports = Class(function(){
81 'use strict';
91 return {
10 gcType: 'FileSession',
11 /**
12 * 差异化的init
13 * @return {[type]} [description]
14 */
15 init: function(options){
160 options = options || {};
170 options.cache_path = C('session_path') || (os.tmpdir() + '/thinkjs');
180 this.super_('init', options);
190 this.key = options.cookie;
20 },
21 initData: function(){
220 if (!this.promise) {
230 var self = this;
240 this.promise = this.getData().then(function(data){
250 self.sessionData = data || {};
26 })
27 }
280 return this.promise;
29 },
30 get: function(name){
310 var self = this;
320 return this.initData().then(function(){
330 return self.sessionData[name];
34 });
35 },
36 set: function(name, value, timeout){
370 var self = this;
380 return this.initData().then(function(){
390 self.sessionData[name] = value;
400 if (timeout) {
410 self.options.timeout = timeout;
42 }
43 });
44 },
45 rm: function(){
460 this.sessionData = {};
470 return getPromise();
48 },
49 /**
50 * 将数据写入到文件中
51 * @return {[type]} [description]
52 */
53 flush: function(){
540 var self = this;
550 return this.initData().then(function(){
560 return self.setData(self.sessionData);
57 })
58 }
59 };
60}, thinkRequire('FileCache'));

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Socket/MemcacheSocket.js

12%
124
15
109
LineHitsSource
11var net = require('net');
21var EventEmitter = require('events').EventEmitter;
3
41var CRLF = '\r\n'; //换行符
51var CRLF_LENGTH = CRLF.length;
61var ERRORS = ['ERROR', 'NOT_FOUND', 'CLIENT_ERROR', 'SERVER_ERROR']; //错误
71var ERRORS_LENGTH = ERRORS.length;
8
9//读取一行数据
101function readLine(string){
110 'use strict';
120 var pos = string.indexOf(CRLF);
130 if (pos > -1) {
140 return string.substr(0, pos);
15 }
160 return string;
17}
18/**
19 * memcache类
20 * @return {[type]} [description]
21 */
221module.exports = Class(function(){
231 'use strict';
241 return {
25 init: function(port, hostname){
260 EventEmitter.call(this);
270 this.port = port || 11211;
280 this.hostname = hostname || 'localhost';
290 this.buffer = '';
300 this.callbacks = []; //回调函数
310 this.handle = null; //socket连接句柄
32 },
33 /**
34 * 建立连接
35 * @return {[type]} [description]
36 */
37 connect: function(){
380 if (this.handle) {
390 return this;
40 }
410 var self = this;
420 var deferred = getDefer();
430 this.handle = net.createConnection(this.port, this.host);
440 this.handle.on('connect', function(){
450 this.setTimeout(0);
460 this.setNoDelay();
470 self.emit('connect');
480 deferred.resolve();
49 });
500 this.handle.on('data', function(data){
510 self.buffer += data.toString();
520 self.handleData();
53 });
540 this.handle.on('end', function(){
550 self.handle.end();
560 self.handle = null;
57 });
580 this.handle.on('close', function(){
590 self.handle = null;
600 self.emit('close');
61 });
620 this.handle.on('timeout', function(){
630 self.handle = null;
640 self.emit('timeout');
65 });
660 this.handle.on('error', function(error){
670 self.handle = null;
680 self.emit('error', error);
69 });
700 this.promise = deferred.promise;
710 return this;
72 },
73 /**
74 * 处理接收的数据
75 * @return {[type]} [description]
76 */
77 handleData: function(){
780 while(this.buffer.length > 0){
790 var result = this.getHandleResult(this.buffer);
800 if(result === false){
810 break;
82 }
830 var value = result[0];
840 var pos = result[1];
850 var error = result[2];
860 if (pos > this.buffer.length) {
870 break;
88 }
890 this.buffer = this.buffer.substring(pos);
900 var callback = this.callbacks.shift();
910 if (callback && callback.callback) {
920 callback.callback(error, value);
93 }
94 }
95 },
96 getHandleResult: function(buffer){
970 if (buffer.indexOf(CRLF) === -1) {
980 return false;
99 }
1000 for(var i = 0; i < ERRORS_LENGTH; i++){
1010 var item = ERRORS[i];
1020 if (buffer.indexOf(item) > -1) {
1030 return this.handleError(buffer);
104 }
105 }
1060 var callback = this.callbacks[0];
1070 if (callback && callback.type) {
1080 return this['handle' + ucfirst(callback.type)](buffer);
109 }
1100 return false;
111 },
112 /**
113 * 处理错误
114 * @param {[type]} buffer [description]
115 * @return {[type]} [description]
116 */
117 handleError: function(buffer){
1180 var line = readLine(buffer);
1190 return [null, line.length + CRLF_LENGTH, line];
120 },
121 /**
122 * 处理获取数据
123 * @param {[type]} buffer [description]
124 * @return {[type]} [description]
125 */
126 handleGet: function(buffer){
1270 var value = null;
1280 var end = 3;
1290 var resultLen = 0;
1300 var firstPos;
1310 if (buffer.indexOf('END') === 0) {
1320 return [value, end + CRLF_LENGTH];
1330 }else if (buffer.indexOf('VALUE') === 0 && buffer.indexOf('END') > -1) {
1340 firstPos = buffer.indexOf(CRLF) + CRLF_LENGTH;
1350 var endPos = buffer.indexOf('END');
1360 resultLen = endPos - firstPos - CRLF_LENGTH;
1370 value = buffer.substr(firstPos, resultLen);
1380 return [value, firstPos + parseInt(resultLen, 10) + CRLF_LENGTH + end + CRLF_LENGTH];
139 }else{
1400 firstPos = buffer.indexOf(CRLF) + CRLF_LENGTH;
1410 resultLen = buffer.substr(0, firstPos).split(' ')[3];
1420 value = buffer.substr(firstPos, resultLen);
1430 return [value, firstPos + parseInt(resultLen) + CRLF_LENGTH + end + CRLF_LENGTH];
144 }
145 },
146 /**
147 * 处理简单数据
148 * @param {[type]} buffer [description]
149 * @return {[type]} [description]
150 */
151 handleSimple: function(buffer){
1520 var line = readLine(buffer);
1530 return [line, line.length + CRLF_LENGTH, null];
154 },
155 /**
156 * 版本号
157 * @param {[type]} buffer [description]
158 * @return {[type]} [description]
159 */
160 handleVersion: function(buffer){
1610 var pos = buffer.indexOf(CRLF);
162 //8 is length of 'VERSION '
1630 var value = buffer.substr(8, pos - 8);
1640 return [value, pos + CRLF_LENGTH, null];
165 },
166 /**
167 * 查询
168 * @param {[type]} query [description]
169 * @param {[type]} type [description]
170 * @param {Function} callback [description]
171 * @return {[type]} [description]
172 */
173 query: function(query, type){
1740 this.connect();
1750 var self = this;
1760 var deferred = getDefer();
1770 var callback = function(error, value){
1780 return error ? deferred.reject(error) : deferred.resolve(value);
179 }
1800 this.promise.then(function(){
1810 self.callbacks.push({type: type, callback: callback});
1820 self.handle.write(query + CRLF);
183 });
1840 return deferred.promise;
185 },
186 /**
187 * 获取
188 * @param {[type]} key [description]
189 * @param {Function} callback [description]
190 * @return {[type]} [description]
191 */
192 get: function(key){
1930 return this.query('get ' + key, 'get');
194 },
195 /**
196 * 存储
197 * @return {[type]} [description]
198 */
199 store: function(key, value, type, lifetime, flags){
2000 lifetime = lifetime || 0;
2010 flags = flags || 0;
2020 var length = Buffer.byteLength(value.toString());
2030 var query = [type, key, flags, lifetime, length].join(' ') + CRLF + value;
2040 return this.query(query, 'simple');
205 },
206 /**
207 * 删除
208 * @param {[type]} key [description]
209 * @param {Function} callback [description]
210 * @return {[type]} [description]
211 */
212 delete: function(key){
2130 return this.query('delete ' + key, 'simple');
214 },
215 /**
216 * 获取版本号
217 * @param {Function} callback [description]
218 * @return {[type]} [description]
219 */
220 version: function(){
2210 return this.query('version', 'version');
222 },
223 /**
224 * 增长
225 * @param {[type]} key [description]
226 * @param {[type]} step [description]
227 * @param {Function} callback [description]
228 * @return {[type]} [description]
229 */
230 increment: function(key, step){
2310 step = step || 1;
2320 return this.query('incr ' + key + ' ' + step, 'simple');
233 },
234 /**
235 * 减少
236 * @param {[type]} key [description]
237 * @param {[type]} step [description]
238 * @param {Function} callback [description]
239 * @return {[type]} [description]
240 */
241 decrement: function(key, step){
2420 step = step || 1;
2430 return this.query('decr ' + key + ' ' + step, 'simple');
244 },
245 /**
246 * 关闭
247 * @return {[type]} [description]
248 */
249 close: function(){
2500 if (this.handle && this.handle.readyState === 'open') {
2510 this.handle.end();
2520 this.handle = null;
253 }
254 }
255 }
256}, EventEmitter).extend(function(){
2571 'use strict';
2581 var result = {};
2591 ['set', 'add', 'replace', 'append', 'prepend'].forEach(function(item){
2605 result[item] = function(key, value, callback, lifetime, flags){
2610 return this.store(key, value, item, callback, lifetime, flags);
262 }
263 });
2641 return result;
265});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Socket/MysqlSocket.js

8%
45
4
41
LineHitsSource
1/**
2 * mysql socket
3 * @return {[type]} [description]
4 */
5
6//暂时使用mysql库
71var mysql = require('mysql');
81module.exports = Class(function(){
91 'use strict';
101 return {
11 init: function(config){
120 this.handle = null;
130 this.config = config;
140 this.deferred = null;
150 this.tryTimes = 0;
16 },
17 /**
18 * 建立数据库连接
19 * @return {[type]} [description]
20 */
21 connect: function(){
220 if (this.handle) {
230 return this.deferred.promise;
24 }
250 var self = this;
260 var deferred = getDefer();
27 //创建连接
280 var connection = mysql.createConnection({
29 host : this.config.hostname || 'localhost',
30 user : this.config.username || 'root',
31 password : this.config.password || '',
32 database : this.config.database || ''
33 });
34 //连接
350 connection.connect(function(err){
36 //连接失败
370 if (err) {
380 deferred.reject(err);
390 self.close();
40 }else{
410 deferred.resolve();
42 }
43 });
44 //错误时关闭当前连接
450 connection.on('error', function(){
460 self.close();
47 });
48 //PROTOCOL_CONNECTION_LOST
490 connection.on('end', function(){
500 self.close();
51 })
52 //连接句柄
530 this.handle = connection;
54 //把上一次的promise reject
550 if (this.deferred) {
560 this.deferred.reject(new Error('connection closed'));
57 }
580 this.deferred = deferred;
590 return this.deferred.promise;
60 },
61 /**
62 * 查询sql语句,返回一个promise
63 * @param {[type]} sql [description]
64 * @return {[type]} [description]
65 */
66 query: function(sql){
670 if (APP_DEBUG) {
680 console.log('sql: ' + sql);
69 }
700 var self = this;
710 return this.connect().then(function(){
720 var deferred = getDefer();
730 self.handle.query(sql, function(err, rows){
740 if (err) {
75 //当数据量非常大时,可能会出现连接丢失,这里进行重连
760 if (err.code === 'PROTOCOL_CONNECTION_LOST' && self.tryTimes < 3) {
770 self.tryTimes++;
780 self.close();
790 return self.query(sql);
80 }
810 return deferred.reject(err);
82 }
830 self.tryTimes = 0;
840 return deferred.resolve(rows || []);
85 });
860 return deferred.promise;
87 });
88 },
89 /**
90 * 关闭连接
91 * @return {[type]} [description]
92 */
93 close: function(){
940 if (this.handle) {
950 this.handle.destroy();
960 this.handle = null;
97 }
98 }
99 };
100});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Template/EjsTemplate.js

100%
6
6
0
LineHitsSource
1/**
2 * ejs
3 * https://github.com/visionmedia/ejs
4 * @type {[type]}
5 */
61var ejs = require('ejs');
71module.exports = {
8 fetch: function(templateFile, tVar){
91 'use strict';
101 var content = getFileContent(templateFile);
111 var conf = extend({
12 filename: templateFile,
13 cache: true
14 }, C('tpl_engine_config'));
151 return ejs.compile(content, conf)(tVar);
16 }
17};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Extend/Controller/RestController.js

75%
4
3
1
LineHitsSource
1/**
2 * REST Controller
3 * @return {[type]} [description]
4 */
51module.exports = Controller(function(){
61 'use strict';
71 return {
8 __before: function(){
9
10 },
11 __call: function(){
120 this.end('method is not allowed');
13 }
14 }
15})

/Users/welefen/Develop/git/thinkjs/lib/Lib/Extend/Model/AdvModel.js

5%
230
12
218
LineHitsSource
1/**
2 * 高级模型
3 * @return {[type]} [description]
4 */
51module.exports = Model(function(){
61 'use strict';
7 //关联类型
81 global.HAS_ONE = 1;
91 global.BELONGS_TO = 2;
101 global.HAS_MANY = 3;
111 global.MANY_TO_MANY = 4;
12
13 //post的操作类型
141 var ADD = 'ADD';
151 var UPDATE = 'UPDATE';
161 var DELETE = 'DELETE';
17
18 //get时不同的type对应的回调
191 var mapTypeGetFn = {
20 1: '_getHasOneRelation',
21 2: '_getBelongsToRelation',
22 3: '_getHasManyRelation',
23 4: '_getManyToManyRelation'
24 };
25
26 //post时不同的type对应的回调
271 var mapTypePostFn = {
28 1: '_postHasOneRelation',
29 2: '_postBelongsToRelation',
30 3: '_postHasManyRelation',
31 4: '_postManyToManyRelation'
32 };
33
341 return {
35 /**
36 * 关联定义
37 * 数据格式:
38 * 'Profile': {
39 type: 1,
40 model: 'Profile',
41 name: 'Profile',
42 key: 'id',
43 fKey: 'user_id',
44 field: 'id,name',
45 where: 'name=xx',
46 order: '',
47 limit: ''
48 * }
49 * @type {Object}
50 */
51 relation: {},
52 /**
53 * 本次使用的关联名称,默认是全部使用
54 * @type {Boolean}
55 */
56 _relationName: true,
57 /**
58 * 只读字段
59 * @type {String}
60 */
61 readonlyField: '',
62 /**
63 * 保存时对数据进行校验
64 * @type {Boolean}
65 */
66 _validateField: true,
67 /**
68 * 字段类型
69 * @type {Object}
70 */
71 fieldType: {},
72 /**
73 * 设置本次使用的relation
74 * @param {[type]} name [description]
75 */
76 setRelation: function(name, value){
770 if (isObject(name) || !isEmpty(value)) {
780 var obj = isObject(name) ? name : getObject(name, value);
790 extend(this.relation, obj);
800 return this;
81 }
820 if (isString(name)) {
830 name = name.split(',');
84 }
850 this._relationName = name;
860 return this;
87 },
88 /**
89 * find后置操作
90 * @param {[type]} data [description]
91 * @return {[type]} [description]
92 */
93 _afterFind: function(data, parsedOptions){
940 return this.getRelation(data, parsedOptions);
95 },
96 /**
97 * select后置操作
98 * @param {[type]} data [description]
99 * @return {[type]} [description]
100 */
101 _afterSelect: function(data, parsedOptions){
1020 return this.getRelation(data, parsedOptions);
103 },
104 /**
105 * 获取关联的数据
106 * @param {[type]} data [description]
107 * @param Boolean isDataList 是否是数据列表
108 * @return {[type]}
109 */
110 getRelation: function(data, parsedOptions){
1110 if (isEmpty(data) || isEmpty(this.relation) || isEmpty(this._relationName)) {
1120 return data;
113 }
1140 var self = this;
1150 var promises = Object.keys(this.relation).map(function(key){
1160 var mapName, mapType, model, mapKey, mapfKey;
1170 var value = self.relation[key];
1180 if (!isObject(value)) {
1190 value = {type: value};
120 }
1210 mapName = value.name || key;
122 //如果不在开启的relation内,则直接返回
1230 if (self._relationName !== true && self._relationName.indexOf(mapName) === -1) {
1240 return;
125 }
1260 mapType = value.type || HAS_ONE;
1270 mapKey = value.key || self.getPk();
1280 mapfKey = value.fKey || (self.name.toLowerCase() + '_id');
1290 model = D(value.model || key);
1300 model.where(value.where).cache(parsedOptions.cache).field(value.field).order(value.order).limit(value.limit);
131 //调用不同的类型解析
1320 return self[mapTypeGetFn[mapType]](data, value, {
133 model: model,
134 mapName: mapName,
135 mapKey: mapKey,
136 mapfKey: mapfKey
137 }, parsedOptions);
138 });
1390 return Promise.all(promises).then(function(){
1400 return data;
141 });
142 },
143 _getHasOneRelation: function(data, value, mapOptions){
1440 var self = this;
1450 var where = self.parseRelationWhere(data, mapOptions.mapKey, mapOptions.mapfKey);
1460 if (where === false) {
1470 return {};
148 }
1490 mapOptions.model.where(where);
1500 return mapOptions.model.select().then(function(mapData){
1510 return self.parseRelationData(data, mapData, mapOptions.mapName, mapOptions.mapKey, mapOptions.mapfKey);
152 });
153 },
154 _getBelongsToRelation: function(data, value, mapOptions){
1550 var self = this;
1560 var mapKey, mapfKey;
1570 return mapOptions.model.getTableFields().then(function(){
1580 mapKey = mapOptions.model.getModelName().toLowerCase() + '_id';
1590 mapfKey = mapOptions.model.getPk();
1600 var where = self.parseRelationWhere(data, mapKey, mapfKey);
1610 if (where === false) {
1620 return {};
163 }
1640 mapOptions.model.where(where);
1650 return mapOptions.model.select().then(function(mapData){
1660 return self.parseRelationData(data, mapData, mapOptions.mapName, mapKey, mapfKey);
167 })
168 })
169 },
170 _getHasManyRelation: function(data, value, mapOptions){
1710 var self = this;
1720 var where = self.parseRelationWhere(data, mapOptions.mapKey, mapOptions.mapfKey);
1730 if (where === false) {
1740 return [];
175 }
1760 mapOptions.model.where(where);
1770 return mapOptions.model.select().then(function(mapData){
1780 return self.parseRelationData(data, mapData, mapOptions.mapName, mapOptions.mapKey, mapOptions.mapfKey, true);
179 });
180 },
181 _getManyToManyRelation: function(data, value, mapOptions, parsedOptions){
1820 var self = this;
1830 return mapOptions.model.getTableFields().then(function(){
1840 var where = self.parseRelationWhere(data, mapOptions.mapKey, mapOptions.mapfKey);
1850 if (where === false) {
1860 return [];
187 }
1880 var whereStr = self.db.parseWhere(where);
189 //关联的实体表和关系表联合查询
1900 var sql = 'SELECT b.%s, a.%s FROM %s as a, %s as b %s AND a.%s=b.%s %s';
1910 var queryData = [
192 value.field || '*',
193 mapOptions.mapfKey,
194 value.rTable || self.getRelationTableName(mapOptions.model),
195 mapOptions.model.getTableName(),
196 whereStr || 'WHERE ',
197 value.rfKey || (mapOptions.model.getModelName().toLowerCase() + '_id'),
198 mapOptions.model.getPk(),
199 value.where ? (' AND ' + value.where) : ''
200 ];
2010 return self.parseSql(sql, queryData).then(function(sql){
2020 return self.db.select(sql, parsedOptions.cache);
203 }).then(function(mapData){
2040 return self.parseRelationData(data, mapData, mapOptions.mapName, mapOptions.mapKey, mapOptions.mapfKey, true);
205 });
206 });
207 },
208 /**
209 * 多对多关系下,获取对应的关联表
210 * @return {[type]} [description]
211 */
212 getRelationTableName: function(model){
2130 var table = [
214 this.tablePrefix,
215 this.tableName || this.name,
216 '_',
217 model.getModelName()
218 ].join('');
2190 return table.toLowerCase();
220 },
221 /**
222 * 多堆垛关系下,回去对应关联表的模型
223 * @param {[type]} model [description]
224 * @return {[type]} [description]
225 */
226 getRelationModel: function(model){
2270 var name = ucfirst(this.tableName || this.name) + ucfirst(model.getModelName());
2280 return D(name);
229 },
230 /**
231 * 解析relation的where条件
232 * @param {[type]} data [description]
233 * @param {[type]} mapKey [description]
234 * @param {[type]} mapfKey [description]
235 * @return {[type]} [description]
236 */
237 parseRelationWhere: function(data, mapKey, mapfKey){
2380 if (isArray(data)) {
2390 var keys = {};
2400 data.forEach(function(item){
2410 keys[item[mapKey]] = 1;
242 })
2430 var value = Object.keys(keys);
2440 if (value.length === 0) {
2450 return false;
246 }
2470 return getObject(mapfKey, ['IN', value]);
248 }
2490 return getObject(mapfKey, data[mapKey]);
250 },
251 /**
252 * 解析查询后的数据
253 * @param {[type]} data [description]
254 * @param {[type]} mapData [description]
255 * @param {[type]} mapName [description]
256 * @param {[type]} mapKey [description]
257 * @param {[type]} mapfKey [description]
258 * @param {Boolean} isArrMap [description]
259 * @return {[type]} [description]
260 */
261 parseRelationData: function(data, mapData, mapName, mapKey, mapfKey, isArrMap){
2620 if (isArray(data)) {
263 //提前初始化,防止mapData为空导致data里的数据没有初始化的情况
2640 data.forEach(function(item, i){
2650 data[i][mapName] = isArrMap ? [] : {};
266 });
2670 mapData.forEach(function(mapItem){
2680 data.forEach(function(item, i){
2690 if (mapItem[mapfKey] !== item[mapKey]) {
2700 return;
271 }
2720 if (isArrMap) {
2730 data[i][mapName].push(mapItem);
274 }else{
2750 data[i][mapName] = mapItem;
276 }
277 });
278 });
279 }else{
2800 data[mapName] = isArrMap ? (mapData || []) : (mapData[0] || {});
281 }
2820 return data;
283 },
284 /**
285 * 添加后置操作
286 * @param {[type]} data [description]
287 * @param {[type]} parsedOptions [description]
288 * @return {[type]} [description]
289 */
290 _afterAdd: function(data, parsedOptions){
2910 return this.postRelation(ADD, data, parsedOptions);
292 },
293 /**
294 * 删除后置操作
295 * @param {[type]} data [description]
296 * @param {[type]} parsedOptions [description]
297 * @return {[type]} [description]
298 */
299 _afterDelete: function(data, parsedOptions){
3000 return this.postRelation(DELETE, data, parsedOptions);
301 },
302 /**
303 * 更新前置操作
304 * @param {[type]} data [description]
305 * @param {[type]} parsedOptions [description]
306 * @return {[type]} [description]
307 */
308 _beforeUpdate: function(data){
309 //只读字段处理
3100 if (!isEmpty(this.readonlyField)) {
3110 if (isString(this.readonlyField)) {
3120 this.readonlyField = this.readonlyField.split(',');
313 }
3140 this.readonlyField.forEach(function(field){
3150 delete data[field];
316 });
317 }
3180 return data;
319 },
320 /**
321 * 更新后置操作
322 * @param {[type]} data [description]
323 * @param {[type]} parsedOptions [description]
324 * @return {[type]} [description]
325 */
326 _afterUpdate: function(data, parsedOptions){
3270 return this.postRelation(UPDATE, data, parsedOptions);
328 },
329 /**
330 * 提交类关联操作
331 * @param {[type]} postType [description]
332 * @param {[type]} data [description]
333 * @param {[type]} parsedOptions [description]
334 * @return {[type]} [description]
335 */
336 postRelation: function(postType, data, parsedOptions){
3370 if (isEmpty(data) || isEmpty(this.relation) || isEmpty(this._relationName)) {
3380 return data;
339 }
3400 var self = this;
3410 var promises = [];
3420 Object.keys(this.relation).forEach(function(key){
3430 var promise, mapName, mapType, model, mapKey, mapfKey, mapData;
3440 var value = self.relation[key];
3450 if (!isObject(value)) {
3460 value = {type: value};
347 }
3480 mapName = value.name || key;
349 //如果没有开启对应的relation,则直接返回
3500 if (self._relationName !== true && self._relationName.indexOf(mapName) === -1) {
3510 return;
352 }
3530 mapData = data[mapName];
354 //如果没有对应的数据,则直接返回
3550 if (isEmpty(mapData) && postType !== DELETE) {
3560 return;
357 }
3580 mapKey = value.key || self.getPk();
3590 if (isEmpty(data[mapKey])) {
3600 return;
361 }
3620 mapType = value.type || HAS_ONE;
3630 mapfKey = value.fKey || (self.name.toLowerCase() + '_id');
3640 model = D(value.model || key);
3650 model.where(value.where);
366 //调用不同的类型解析
3670 promise = self[mapTypePostFn[mapType]](data, value, {
368 model: model,
369 mapName: mapName,
370 mapKey: mapKey,
371 mapfKey: mapfKey,
372 mapData: mapData,
373 type: postType
374 }, parsedOptions);
375
3760 promises.push(promise);
377 });
3780 return Promise.all(promises).then(function(){
3790 return data;
380 });
381 },
382 /**
383 * 一对一提交
384 * @param {[type]} data [description]
385 * @param {[type]} value [description]
386 * @param {[type]} mapOptions [description]
387 * @param {[type]} parsedOptions [description]
388 * @return {[type]} [description]
389 */
390 _postHasOneRelation: function(data, value, mapOptions){
3910 var promise = null;
3920 var where;
3930 switch(mapOptions.type){
394 case ADD:
3950 mapOptions.mapData[mapOptions.mapfKey] = data[mapOptions.mapKey];
3960 promise = mapOptions.model.add(mapOptions.mapData);
3970 break;
398 case DELETE:
3990 where = getObject(mapOptions.mapfKey, data[mapOptions.mapKey]);
4000 promise = mapOptions.model.where(where).delete();
4010 break;
402 case UPDATE:
4030 where = getObject(mapOptions.mapfKey, data[mapOptions.mapKey]);
4040 promise = mapOptions.model.where(where).update(mapOptions.mapData);
4050 break;
406 default:
4070 break;
408 }
4090 return promise;
410 },
411 _postBelongsToRelation: function(data){
4120 return data;
413 },
414 /**
415 * 一对多提交
416 * @param {[type]} data [description]
417 * @param {[type]} value [description]
418 * @param {[type]} mapOptions [description]
419 * @param {[type]} parsedOptions [description]
420 * @return {[type]} [description]
421 */
422 _postHasManyRelation: function(data, value, mapOptions){
4230 var type = mapOptions.type;
4240 var mapData = mapOptions.mapData;
4250 var model = mapOptions.model;
4260 var promise;
4270 if (!isArray(mapData)) {
4280 mapData = [mapData];
429 }
4300 switch(type){
431 case ADD:
4320 mapData = mapData.map(function(item){
4330 item[mapOptions.mapfKey] = data[mapOptions.mapKey];
434 });
4350 promise = model.addAll(mapData);
4360 break;
437 case UPDATE:
4380 promise = model.getTableFields().then(function(){
4390 var promises = [];
4400 var pk = model.getPk();
4410 mapData.forEach(function(item){
4420 var pro;
4430 if (item[pk]) {
4440 pro = model.update(item);
445 }else{
4460 item[mapOptions.mapfKey] = data[mapOptions.mapKey];
4470 pro = model.add(item);
448 }
4490 promises.push(pro);
450 });
4510 return Promise.all(promises);
452 });
4530 break;
454 case DELETE:
4550 var where = getObject(mapOptions.mapfKey, data[mapOptions.mapKey]);
4560 promise = model.where(where).delete();
4570 break;
458 }
4590 return promise;
460 },
461 /**
462 * 多对多提交
463 * @param Object data [description]
464 * @param object value [description]
465 * @param {[type]} mapOptions [description]
466 * @param {[type]} parsedOptions [description]
467 * @return {[type]} [description]
468 */
469 _postManyToManyRelation: function(data, value, mapOptions){
4700 var self = this;
4710 var model = mapOptions.model;
4720 var promise = model.getTableFields();
4730 var rfKey = value.rfKey || (model.getModelName().toLowerCase() + '_id');
474 //var relationTable = value.rTable || self.getRelationTableName(model);
4750 var where;
4760 var type = mapOptions.type;
4770 var mapData = mapOptions.mapData;
4780 var relationModel = self.getRelationModel(model);
4790 if (type === DELETE || type === UPDATE) {
4800 where = getObject(mapOptions.mapfKey, data[mapOptions.mapKey]);
4810 promise = promise.then(function(){
4820 return relationModel.where(where).delete();
483 });
484 }
4850 if (type === ADD || type === UPDATE) {
4860 promise = promise.then(function(){
4870 if (!isArray(mapData)) {
4880 mapData = isString(mapData) ? mapData.split(',') : [mapData];
489 }
4900 var firstItem = mapData[0];
491 //关系数据
4920 if (isNumberString(firstItem) || (isObject(firstItem) && (rfKey in firstItem))) {
493 //生成要更新的数据
4940 var postData = mapData.map(function(item){
4950 var key = [mapOptions.mapfKey, rfKey];
4960 var val = [data[mapOptions.mapKey], item[rfKey] || item];
4970 return getObject(key, val);
498 });
4990 return relationModel.addAll(postData);
500 }else{ //实体数据
5010 var unqiueField = model.getUniqueField();
5020 if (!unqiueField) {
5030 return getPromise(model.getTableName() + ' table has no unqiue field', true);
504 }
5050 return self._getRalationAddIds(mapData, model, unqiueField).then(function(ids){
5060 var postData = ids.map(function(id){
5070 var key = [mapOptions.mapfKey, rfKey];
5080 var val = [data[mapOptions.mapKey], id];
5090 return getObject(key, val);
510 });
5110 return relationModel.addAll(postData);
512 });
513 }
514 });
515 }
5160 return promise;
517 },
518 /**
519 * 插入数据,并获取插入的id集合
520 * @param {[type]} dataList [description]
521 * @param {[type]} model [description]
522 * @param {[type]} unqiueField [description]
523 * @return {[type]} [description]
524 */
525 _getRalationAddIds: function(dataList, model, unqiueField){
5260 var promises = [];
5270 var ids = [];
5280 dataList.forEach(function(item){
5290 if (!isObject(item)) {
5300 item = getObject(unqiueField, item);
531 }
5320 var value = item[unqiueField];
5330 if (!value) {
5340 return true;
535 }
5360 var where = getObject(unqiueField, value);
5370 var promise = model.where(where).field(model.getPk()).find().then(function(data){
5380 if (isEmpty(data)) {
5390 return model.add(item).then(function(insertId){
5400 ids.push(insertId);
541 });
542 }else{
5430 ids.push(data[model.getPk()]);
544 }
545 });
5460 promises.push(promise);
547 });
5480 return Promise.all(promises).then(function(){
5490 return ids;
550 });
551 },
552 /**
553 * 设置是否对数据进行校验
554 * @param {[type]} validate [description]
555 * @return {[type]} [description]
556 */
557 validate: function(validate){
5580 this._validateField = validate;
559 }
560 };
561});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Behavior.js

100%
7
7
0
LineHitsSource
1/**
2 * 行为类
3 * @return {[type]} [description]
4 */
51module.exports = Class(function(){
61 'use strict';
71 return {
8 options: {}, //行为选项
9 http: null,
10 init: function(http){
116 this.http = http;
126 for(var name in this.options){
1310 if (C(name) !== undefined) {
149 this.options[name] = C(name);
15 }
16 }
17 },
18 run: function(){
19
20 }
21 };
22});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Cache.js

11%
54
6
48
LineHitsSource
1/**
2 * 缓存基类
3 * @return {[type]} [description]
4 */
5/**
6 * 缓存数据
7 * @type {Object}
8 */
91var cacheData = {};
10/**
11 * 定时器
12 * @type {Number}
13 */
141var gcTimer = {};
15/**
16 * 清除已经过期的Cache
17 * @return {[type]} [description]
18 */
191var gc = function(instance){
200 'use strict';
210 if (APP_DEBUG || APP_MODE === 'cli' || gcTimer[instance.gcType]) {
220 return;
23 }
240 gcTimer[instance.gcType] = setInterval(function(){
250 var hour = (new Date()).getHours();
260 if (C('cache_gc_hour').indexOf(hour) === -1) {
270 return;
28 }
290 var now = Date.now();
300 if (instance.gc) {
310 console.log('gc clean: ', instance.gcType, (new Date()).toUTCString());
320 instance.gc(now);
33 }
34 }, 3600 * 1000);
35};
36
371module.exports = Class(function(){
381 'use strict';
391 return {
40 /**
41 * gc的类型,用于定时器类型判断
42 * @type {String}
43 */
44 gcType: 'Cache',
45 /**
46 * 初始化
47 * @param {[type]} options [description]
48 * @return {[type]} [description]
49 */
50 init: function(options){
510 options = options || {};
520 if (options.cacheData) {
530 this.cacheData = options.cacheData;
54 }else{
550 this.cacheData = cacheData;
56 }
570 if (options.gcType) {
580 this.gcType = options.gcType;
59 }
600 if (!options.timeout) {
610 options.timeout = C('cache_timeout')
62 }
630 this.options = options;
64 //操作的key
650 this.key = '';
66 //是否更新expire值
670 this.updateExpire = false;
680 gc(this);
69 },
70 /**
71 * 获取缓存值,返回一个promise
72 * @param {[type]} name [description]
73 * @return {[type]} [description]
74 */
75 get: function(name){
760 var key = this.key || name;
770 if (!(key in this.cacheData)) {
780 return getPromise();
79 }
800 var value = this.cacheData[key];
810 if (Date.now() > value.expire) {
820 delete this.cacheData[key];
830 return getPromise();
84 }
850 if (this.updateExpire) {
860 this.cacheData[key].expire = Date.now() + value.timeout * 1000;
87 }
880 return getPromise(value.data[name]);
89 },
90 /**
91 * 设置缓存值
92 * @param {[type]} name [description]
93 * @param {[type]} value [description]
94 */
95 set: function(name, value, timeout){
960 if (timeout === undefined) {
970 timeout = this.options.timeout;
98 }
990 var key = this.key || name;
1000 if (key in this.cacheData) {
1010 this.cacheData[key].data[name] = value;
102 }else{
1030 this.cacheData[key] = {
104 data: getObject(name, value),
105 timeout: timeout,
106 expire: Date.now() + timeout * 1000
107 };
108 }
1090 return getPromise();
110 },
111 /**
112 * 移除缓存值
113 * @param {[type]} name [description]
114 * @return {[type]} [description]
115 */
116 rm: function(name){
1170 var key = this.key || name;
1180 if (key in this.cacheData) {
1190 delete this.cacheData[key].data[name];
120 }
1210 return getPromise();
122 },
123 /**
124 * gc
125 * @param {[type]} now [description]
126 * @return {[type]} [description]
127 */
128 gc: function(now){
1290 for(var key in this.cacheData){
1300 var item = this.cacheData[key] || {};
1310 if (now > item.expire) {
1320 delete this.cacheData[key];
133 }
134 }
135 }
136 };
137});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Cookie.js

22%
35
8
27
LineHitsSource
1/**
2 * cookie操作
3 * @type {Object}
4 */
51module.exports = {
6 /**
7 * 解析
8 * @param {[type]} str [description]
9 * @return {[type]} [description]
10 */
11 parse: function(str){
121 'use strict';
131 var data = {};
141 str.split(/[;,] */).forEach(function(item) {
151 var pos = item.indexOf('=');
161 if (pos === -1) {
171 return;
18 }
190 var key = item.substr(0, pos).trim();
200 var val = item.substr(++pos, item.length).trim();
210 if ('"' === val[0]) {
220 val = val.slice(1, -1);
23 }
24 // only assign once
250 if (undefined === data[key]) {
260 try {
270 data[key] = decodeURIComponent(val);
28 } catch (e) {
290 data[key] = val;
30 }
31 }
32 });
331 return data;
34 },
35 /**
36 * 格式化
37 * @param {[type]} name [description]
38 * @param {[type]} val [description]
39 * @param {[type]} options [description]
40 * @return {[type]} [description]
41 */
42 stringify: function(name, value, options){
430 'use strict';
440 options = options || {};
450 var item = [name + '=' + encodeURIComponent(value)];
460 if (options.maxage) {
470 item.push('Max-Age=' + options.maxage);
48 }
490 if (options.domain) {
500 item.push('Domain=' + options.domain);
51 }
520 if (options.path) {
530 item.push('Path=' + options.path);
54 }
550 var expires = options.expires;
560 if (expires){
570 if (!isDate(expires)) {
580 expires = new Date(expires);
59 }
600 item.push('Expires=' + expires.toUTCString());
61 }
620 if (options.httponly) {
630 item.push('HttpOnly');
64 }
650 if (options.secure) {
660 item.push('Secure');
67 }
680 return item.join('; ');
69 }
70}

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Filter.js

3%
54
2
52
LineHitsSource
1/**
2 * 过滤器
3 * @return {[type]} [description]
4 */
51var Filter = module.exports = {
6 /**
7 * 分页
8 * @param {[type]} value [description]
9 * @return {[type]} [description]
10 */
11 page: function(value){
120 'use strict';
130 return this.id(value) || 1;
14 },
15 /**
16 * xxx asc,yyy desc
17 * @return {[type]} [description]
18 */
19 order: function(value){
200 'use strict';
210 if (isString(value)) {
220 value = value.split(',');
23 }
240 if (!isArray(value)) {
250 return '';
26 }
270 return value.filter(function(item){
280 item = item.trim().split(' ');
290 var field = item[0];
300 var type = item[1];
310 if (/^(ASC|DESC)$/i.test(type) && /^[\w]+$/.test(field)) {
320 return field + ' ' + type;
33 }
34 }).join(',');
35 },
36 /**
37 * 大于0
38 * @return {[type]} [description]
39 */
40 id: function(value){
410 'use strict';
420 value = parseInt(value + '', 10);
430 if (value > 0) {
440 return value;
45 }
460 return 0;
47 },
48 /**
49 * id列表
50 * @return {[type]} [description]
51 */
52 ids: function(value, split){
530 'use strict';
540 if (isNumber(value)) {
550 value = this.id(value);
560 if (value) {
570 return [value];
58 }
590 return [];
60 }
610 if (isString(value)) {
620 value = value.split(split || ',');
63 }
640 if (!isArray(value)) {
650 return [];
66 }
670 return value.filter(function(item){
680 item = (item + '').trim();
690 item = parseInt(item, 10);
700 return item;
71 });
72 },
73 /**
74 * 是否在一个中
75 * @param {[type]} value [description]
76 * @param {[type]} arr [description]
77 * @return {[type]} [description]
78 */
79 in: function(value, arr){
800 'use strict';
810 if (!isArray(arr)) {
820 arr = [arr];
83 }
840 if(arr.indexOf(value) > -1){
850 return value;
86 }
870 return '';
88 },
89 /**
90 * 将字符串切割为数组
91 * @param {[type]} value [description]
92 * @param {[type]} split [description]
93 * @return {[type]} [description]
94 */
95 strs: function(value, split){
960 'use strict';
970 if (isString(value)) {
980 value = value.split(split || ',');
99 }
1000 if (!isArray(value)) {
1010 return [];
102 }
1030 return value.filter(function(item){
1040 return (item + '').trim();
105 });
106 }
107};
108/**
109 * 调用一个过滤器
110 * @param {[type]} data [description]
111 * @param {[type]} type [description]
112 * @return {[type]} [description]
113 */
1141Filter.filter = function(value, type){
1150 'use strict';
1160 var fn = Filter[type];
1170 if (typeof fn === 'function') {
1180 var args = [].slice.call(arguments, 2);
1190 args.unshift(value);
1200 return Filter[type].apply(Filter, args);
121 }
1220 return false;
123};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Session.js

16%
50
8
42
LineHitsSource
11var crypto = require('crypto');
2/**
3 * 生成uid
4 * @param int length
5 * @return string
6 */
71var uid = function(length){
80 'use strict';
90 var ratio = Math.log(64) / Math.log(256);
100 var numbytes = Math.ceil(length * ratio);
110 var str = crypto.randomBytes(numbytes).toString('base64').slice(0, length);
120 return str.replace(/\+/g, '_').replace(/\//g, '-');
13};
14/**
15 * 生成cookie签名
16 * @param string val
17 * @param string secret
18 * @return string
19 */
201var cookieSign = function(val, secret){
210 'use strict';
220 secret = crypto.createHmac('sha256', secret).update(val).digest('base64');
230 secret = secret.replace(/\=+$/, '');
240 return val + '.' + secret;
25};
26/**
27 * 解析cookie签名
28 * @param {[type]} val
29 * @param {[type]} secret
30 * @return {[type]}
31 */
321var cookieUnsign = function(val, secret){
330 'use strict';
340 var str = val.slice(0, val.lastIndexOf('.'));
350 return cookieSign(str, secret) === val ? str : false;
36};
37
381var Session = module.exports = Cache(function(){
391 'use strict';
401 return {
41 init: function(options){
420 this.super_('init', options);
430 this.key = this.options.cookie;
440 this.updateExpire = true;
45 }
46 };
47});
48
491Session.start = function(http){
500 'use strict';
510 if (http.session) {
520 return http.session;
53 }
540 var name = C('session_name');
55 //是否使用签名
560 var secret = C('session_sign');
570 var cookie = http.cookie[name];
580 if (cookie && secret) {
590 cookie = cookieUnsign(cookie, secret);
60 }
610 var session_cookie = cookie;
620 if (!cookie) {
630 cookie = uid(32);
640 session_cookie = cookie;
650 if (secret) {
660 cookie = cookieSign(cookie, secret);
67 }
680 http.setCookie(name, cookie, C('session_options'));
69 }
700 var type = C('session_type');
710 if (!type && APP_DEBUG) {
720 type = 'File';
730 console.log("in debug mode, session can't use memory type for storage, convert to File type");
74 }
75 //使用cluster的时候,不能使用内存来缓存Session
760 if (!type && C('use_cluster')) {
770 type = 'File';
780 console.log("in cluster mode, session can't use memory type for storage, convert to File type")
79 }
800 name = type + 'Session';
81 //session类
820 var session = http.session = thinkRequire(name)({
83 cookie: session_cookie,
84 timeout: C('session_timeout')
85 });
86 //afterend时刷新缓存
870 http.on('afterEnd', function(){
88 //刷新session
890 return session.flush && session.flush();
90 })
910 return cookie;
92};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Valid.js

7%
70
5
65
LineHitsSource
1/**
2 * Valid类
3 * @return {[type]} [description]
4 */
51var net = require('net');
61var Valid = module.exports = Class(function(){
71 'use strict';
81 return {
9 field: '',
10 init: function(field){
110 this.field = field;
12 },
13 /**
14 * 长度区域
15 * @param {[type]} min [description]
16 * @param {[type]} max [description]
17 * @return {[type]} [description]
18 */
19 length: function(min, max){
200 min = min | 0;
210 var length = this.field.length;
220 if (length < min) {
230 return false;
24 }
250 if (max) {
260 if (length > max) {
270 return false;
28 }
29 }
300 return true;
31 },
32 /**
33 * 必填
34 * @return {[type]} [description]
35 */
36 required: function(){
370 return (this.field + '').length > 0;
38 },
39 /**
40 * 自定义正则校验
41 * @param {[type]} reg [description]
42 * @return {[type]} [description]
43 */
44 regexp: function(reg){
450 return reg.test(this.field);
46 },
47 /**
48 * 邮箱
49 * @return {[type]} [description]
50 */
51 email: function(){
520 return this.regexp(/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/);
53 },
54 /**
55 * 时间戳
56 * @return {[type]} [description]
57 */
58 time: function(){
590 return this.regexp(/^(([0-1]\d)|(2[0-3])):[0-5]\d:[0-5]\d$/);
60 },
61 /**
62 * 中文名
63 * @return {[type]} [description]
64 */
65 cnname: function(){
660 return this.regexp(/^[\u4e00-\u9fa5a-zA-Z.\u3002\u2022]{2,32}$/);
67 },
68 /**
69 * 身份证号码
70 * @return {[type]} [description]
71 */
72 idnumber: function(){
730 if (/^\d{15}$/.test(this.field)) {
740 return true;
75 }
760 if ((/^\d{17}[0-9xX]$/).test(this.field)) {
770 var vs = '1,0,x,9,8,7,6,5,4,3,2'.split(','),
78 ps = '7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2'.split(','),
79 ss = this.field.toLowerCase().split(''),
80 r = 0;
810 for (var i = 0; i < 17; i++) {
820 r += ps[i] * ss[i];
83 }
840 var isOk = (vs[r % 11] === ss[17]);
850 return isOk;
86 }
870 return false;
88 },
89 /**
90 * 手机号
91 * @return {[type]} [description]
92 */
93 mobile: function(){
940 return this.regexp(/^(13|15|18|14)\d{9}$/);
95 },
96 /**
97 * 邮编
98 * @return {[type]} [description]
99 */
100 zipcode: function(){
1010 return this.regexp(/^\d{6}$/);
102 },
103 /**
104 * 2次值是否一致
105 * @param {[type]} field [description]
106 * @return {[type]} [description]
107 */
108 confirm: function(field){
1090 return this.field === field;
110 },
111 /**
112 * url
113 * @return {[type]} [description]
114 */
115 url: function(){
1160 return this.regexp(/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/);
117 },
118 /**
119 * 整数
120 * @param {[type]} o [description]
121 * @return {[type]} [description]
122 */
123 int: function(){
1240 var value = parseInt(this.field, 0 || 10);
1250 if (isNaN(value)) {
1260 return false;
127 }
1280 return (value + '').length === this.field.length;
129 },
130 /**
131 * 浮点数
132 * @return {[type]} [description]
133 */
134 float: function(){
1350 var value = parseFloat(this.field);
1360 if (isNaN(value)) {
1370 return false;
138 }
1390 return (value + '').length === this.field.length;
140 },
141 /**
142 * 整数范围
143 * @param {[type]} min [description]
144 * @param {[type]} max [description]
145 * @return {[type]} [description]
146 */
147 range: function(min, max){
1480 var isInt = this.int();
1490 if (!isInt) {
1500 return false;
151 }
1520 return this.field >= min && this.field <= max;
153 },
154 /**
155 * ip4校验
156 * @return {[type]} [description]
157 */
158 ip4: function(){
1590 return net.isIPv4(this.field);
160 },
161 /**
162 * ip6校验
163 * @return {[type]} [description]
164 */
165 ip6: function(){
1660 return net.isIPv6(this.field);
167 },
168 /**
169 * ip校验
170 * @return {[type]} [description]
171 */
172 ip: function(){
1730 return net.isIP(this.field);
174 },
175 /**
176 * 日期校验
177 * @return {[type]} [description]
178 */
179 date: function(){
1800 var reg = /^\d{4}-\d{1,2}-\d{1,2}$/;
1810 return this.regexp(reg);
182 }
183 };
184});
185/**
186 * data格式
187 * [{
188 * value: xxx,
189 * name: '',
190 * valid: ['required', 'range'],
191 * range_args: [],
192 * msg:{
193 * required: '',
194 * range: ''
195 * }
196 * },{
197 * value: xxx,
198 * name: '',
199 * valid: ['required', 'range'],
200 * range_args: [],
201 * msg:{
202 * required: '',
203 * range: ''
204 * }
205 * }]
206 * @param {[type]} data [description]
207 * @return {[type]} [description]
208 */
2091Valid.check = function(data){
2100 'use strict';
2110 data = data ||[];
2120 var result = {};
2130 data.forEach(function(item){
2140 var valid = item.valid;
2150 if (!isArray(valid)) {
2160 valid = [valid];
217 }
2180 var instance = Valid(item.value);
2190 valid.some(function(validItem){
2200 var flag;
2210 if (typeof validItem === 'function') {
2220 flag = validItem(item.value, item);
2230 if (typeof flag === 'string') {
2240 result[item.name] = flag;
2250 return true;
226 }
2270 return false;
228 }
2290 flag = instance[validItem].apply(instance, item[validItem + '_args'] || []);
2300 if (!flag) {
2310 result[item.name] = item.msg[validItem];
2320 return true;
233 }
234 });
235 });
2360 return result;
237};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/WebSocket.js

8%
107
9
98
LineHitsSource
11var thinkHttp = thinkRequire('Http');
21var url = require('url');
31var websocket = require('websocket').server;
41var querystring = require('querystring');
5
61var WebSocket = module.exports = Class(function(){
71 'use strict';
8 /**
9 * socket初始化id
10 * @type {Number}
11 */
121 var socketId = 1000;
131 return {
14 init: function(httpServer, app){
150 this.httpServer = httpServer;
160 this.app = app;
17 },
18 /**
19 * 检测origin是否合法
20 * @param {[type]} origin [description]
21 * @return {[type]} [description]
22 */
23 originIsAllowed: function(origin){
240 var allowOrigins = C('websocket_allow_origin');
250 if (!allowOrigins) {
260 return true;
27 }
280 var info = url.parse(origin);
290 var hostname = info.hostname;
300 if (isString(allowOrigins) && allowOrigins === hostname) {
310 return true;
320 }else if (isArray(allowOrigins) && allowOrigins.indexOf(hostname) > -1) {
330 return true;
340 }else if (isFunction(allowOrigins)) {
350 return allowOrigins(hostname, info);
36 }
370 return false;
38 },
39 /**
40 * 选择子协议
41 * @param {[type]} protocolFullCaseMap [description]
42 * @return {[type]} [description]
43 */
44 getSubProtocal: function(protocolFullCaseMap){
450 var selectedProtocal = C('websocket_sub_protocal');
460 if (isFunction(selectedProtocal)) {
470 var subProtocals = Object.values(protocolFullCaseMap);
480 selectedProtocal = selectedProtocal(subProtocals);
49 }
500 return selectedProtocal;
51 },
52 /**
53 * 建立连接处理
54 * @param {[type]} request [description]
55 * @return {[type]} [description]
56 */
57 openHandle: function(request, protocal){
580 var req = request.httpRequest;
590 if (req.url === '/') {
600 return getPromise([]);
61 }
620 var deferred = getDefer();
630 var fn = function(){};
640 var res = {setHeader: fn, end: fn, write: fn};
650 var self = this;
660 thinkHttp(req, res).run(function(http){
670 http.websocket = request.socket;
68 //子协议
690 http.websocket_sub_protocal = protocal;
700 self.app.listener(http).then(function(){
710 deferred.resolve({
72 cookie: Object.values(http._cookie),
73 http: http
74 });
75 }).catch(function(err){
760 deferred.reject(err);
77 })
78 });
790 return deferred.promise;
80 },
81 /**
82 * 消息处理
83 * @return {[type]} [description]
84 */
85 messageHandle: function(message, connection, app, type){
860 if (type !== 'utf8') {
870 connection.socket.send(WebSocket.ERROR_MESSAGE.TYPE_ERROR, message + ' is not valid json');
880 return;
89 }
90 //解析数据
910 try{
920 message = JSON.parse(message);
93 }catch(e){
940 connection.socket.send(WebSocket.ERROR_MESSAGE.INVALID_JSON, message + ' is not valid json');
950 return;
96 }
970 if (message.jsonrpc !== '2.0') {
980 connection.socket.send(WebSocket.ERROR_MESSAGE.INVALID_JSONRPC, 'data.jsonrpc must be 2.0');
990 return;
100 }
1010 var method = message.method + '';
1020 if (!method) {
1030 connection.socket.send(WebSocket.ERROR_MESSAGE.INVALID_METHOD, 'data.method is not valid');
1040 return;
105 }
1060 var pars = message.params;
1070 var headers = {};
1080 if (isObject(message.params.headers)) {
1090 headers = message.params.headers;
1100 pars = message.params.data;
111 }
1120 if (isObject(pars)) {
1130 method += (method.indexOf('?') > -1 ? '&' : '?') + querystring.stringify(pars)
114 }
1150 var self = this;
1160 var data = {
117 host: '',
118 url: method,
119 headers: headers,
120 write: function(data, encoding, errMsg){
1210 var pars = self.getRPCData(JSON.parse(data), errMsg);
1220 pars.id = message.id;
1230 connection.send(JSON.stringify(pars));
124 },
125 end: function(data){
1260 if (data) {
1270 this.write(data);
128 }
1290 connection.close();
130 }
131 }
1320 var defaultHttp = thinkHttp.getDefaultHttp(data);
1330 var httpInstance = thinkHttp(defaultHttp.req, defaultHttp.res);
134 //将websocket实例添加到http对象上
1350 httpInstance.http.websocket = connection.socket;
1360 httpInstance.run(app.listener);
137 },
138 /**
139 * 获取rpc数据对象
140 * @param {[type]} data [description]
141 * @param {[type]} errMsg [description]
142 * @return {[type]} [description]
143 */
144 getRPCData: function(data, errMsg){
1450 var pars = {jsonrpc: '2.0'};
1460 if (errMsg) {
1470 pars.error = {code: data, message: errMsg};
148 }else{
1490 pars.result = data;
150 }
1510 return pars;
152 },
153 run: function(){
1540 var instance = new websocket({
155 httpServer: this.httpServer,
156 autoAcceptConnections: false
157 });
1580 var self = this;
1590 instance.on('request', function(request){
160 //检测origin
1610 if (!self.originIsAllowed(request.origin)) {
1620 return request.reject();
163 }
1640 var socket = request.socket;
1650 socket.id = socketId++;
1660 socket.activeTime = Date.now();
167 //选择子协议
1680 var protocal = self.getSubProtocal(request.protocolFullCaseMap);
1690 return self.openHandle(request, protocal).then(function(data){
1700 var connection = socket.connection = request.accept(protocal, request.origin, data.cookie);
1710 socket.close = function(){
1720 connection.close();
173 }
1740 if (!socket.send) {
1750 socket.send = function(data, errMsg){
1760 var pars = self.getRPCData(data, errMsg);
1770 connection.send(JSON.stringify(pars));
178 }
179 }
1800 var messageHandle = C('websocket_message_handle');
1810 connection.on('message', function(message) {
1820 socket.activeTime = Date.now();
1830 var data = message.type === 'utf8' ? message.utf8Data : message.binaryData;
1840 if (isFunction(messageHandle)) {
1850 messageHandle(data, connection, self.app, message.type);
186 }else{
1870 self.messageHandle(data, connection, self.app, message.type);
188 }
189 });
1900 connection.on('close', function() {
1910 data.http.emit('websocket.close');
192 });
193 }).catch(function(err){
1940 request.reject(err);
195 })
196 })
197 }
198 }
199});
200/**
201 * 错误信息
202 * @type {Object}
203 */
2041WebSocket.ERROR_MESSAGE = {
205 TYPE_ERROR: -100001, //数据类型错误
206 INVALID_JSON: -100002, //不是合法的json
207 INVALID_JSONRPC: -100003, //不是jsonrpc数据格式
208 INVALID_METHOD: -100004 //请求方法不合法
209}

/Users/welefen/Develop/git/thinkjs/lib/think.js

100%
12
12
0
LineHitsSource
11var path = require('path');
21var fs = require('fs');
3
4//APP根目錄
51global.APP_PATH = global.APP_PATH ? path.normalize(global.APP_PATH) : path.dirname(__dirname) + '/App';
6//RUNTIME目录
71global.RUNTIME_PATH = global.RUNTIME_PATH ? path.normalize(global.RUNTIME_PATH) : global.APP_PATH + '/Runtime';
8//DEBUG模式
91global.APP_DEBUG = global.APP_DEBUG || false;
10//静态资源文件的根目录
111global.RESOURCE_PATH = global.RESOURCE_PATH || '';
12//THINKJS的根目录
131global.THINK_PATH = __dirname;
14//默认为http模式
151global.APP_MODE = 'http';
16//命令行模式
171if (process.argv[2]) {
181 APP_MODE = 'cli';
19}
20//从package.json文件里获取版本号
211global.THINK_VERSION = JSON.parse(fs.readFileSync(global.THINK_PATH + '/../package.json', 'utf8')).version;
22//启动
231require(global.THINK_PATH + '/Lib/Core/Think.js').start();
\ No newline at end of file diff --git a/lib/Common/function.js b/lib/Common/function.js index f7ccc6f7..79fc98e8 100644 --- a/lib/Common/function.js +++ b/lib/Common/function.js @@ -9,7 +9,7 @@ var _autoload_callbacks = []; * @param {[type]} name [description] * @return {[type]} [description] */ -function getThinkRequirePath(name){ +global.getThinkRequirePath = function(name){ 'use strict'; if (_alias[name]) { return _alias[name]; @@ -113,6 +113,7 @@ global.tag = function(name, http, data){ } var result = B(behavior, http, http.tag_data); return getPromise(result).then(function(data){ + //如果返回值不是undefined,那么认为有返回值 if (data !== undefined) { http.tag_data = data; } @@ -134,6 +135,7 @@ global.C = function(name, value){ //清除所有的配置 if (name === null) { _config = {}; + return; } if (isString(name)) { name = name.toLowerCase(); @@ -164,13 +166,8 @@ global.C = function(name, value){ */ global.A = function(name, http, data){ 'use strict'; - if (name.indexOf('/') > -1) { - name = name.split('/'); - }else if (name.indexOf(':') > -1) { - name = name.split(':'); - }else{ - name = [name]; - } + //将/转为:,兼容之前的方式 + name = name.replace(/\//g, ':').split(':'); var action; if (name.length === 3) { action = name.pop(); diff --git a/lib/Conf/alias.js b/lib/Conf/alias.js index a37ca6b0..6441e0f8 100644 --- a/lib/Conf/alias.js +++ b/lib/Conf/alias.js @@ -12,7 +12,7 @@ module.exports = { Dispatcher: THINK_LIB_PATH + '/Core/Dispatcher.js', Filter: THINK_LIB_PATH + '/Util/Filter.js', Http: THINK_LIB_PATH + '/Core/Http.js', - Log: THINK_LIB_PATH + '/Util/Log.js', + //Log: THINK_LIB_PATH + '/Util/Log.js', Model: THINK_LIB_PATH + '/Core/Model.js', Session: THINK_LIB_PATH + '/Util/Session.js', Think: THINK_LIB_PATH + '/Core/Think.js', diff --git a/lib/Conf/config.js b/lib/Conf/config.js index 22810d0c..c9060466 100644 --- a/lib/Conf/config.js +++ b/lib/Conf/config.js @@ -26,8 +26,8 @@ module.exports = { default_action: 'index', //默认Action call_controller: 'Home:Index:_404', //controller不存在时执行方法,此配置表示调用Home分组下IndexController的_404Action方法 call_method: '__call', //当找不到方法时调用什么方法,这个方法存在时才有效 - before_action_name: '__before', //调用一个action前调用的方法,会将action名传递进去 - after_action_name: '__after', //调用一个action之后调用的方法,会将action名传递进去 + before_action: '__before', //调用一个action前调用的方法,会将action名传递进去 + after_action: '__after', //调用一个action之后调用的方法,会将action名传递进去 url_params_bind: true, //方法参数绑定,将URL参数值绑定到action的参数上 action_suffix: 'Action', //action后缀 url_callback_name: 'callback', //jsonp格式的callback名字 diff --git a/lib/Lib/Core/App.js b/lib/Lib/Core/App.js index e43ebfb5..2f649e8d 100644 --- a/lib/Lib/Core/App.js +++ b/lib/Lib/Core/App.js @@ -1,176 +1,173 @@ var cluster = require('cluster'); var fs = require('fs'); var domain = require('domain'); + var thinkHttp = thinkRequire('Http'); var Dispatcher = thinkRequire('Dispatcher'); -/** - * 应用程序 - * @type {Object} - */ -var App = module.exports = Class(function(){ - 'use strict'; - //controller和action的校验正则 - var nameReg = /^[A-Za-z\_](\w)*$/; - //注释的正则 - var commentReg = /((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg; - //获取形参的正则 - var parsReg = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; +//注释的正则 +var commentReg = /((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg; +//获取形参的正则 +var parsReg = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; - return { - init: function(http){ - this.http = http; - }, - /** - * 解析路由 - * @return {[type]} [description] - */ - dispatch: function(){ - return Dispatcher(this.http).run(); - }, - /** - * 获取controller - * @return {[type]} [description] - */ - getController: function(){ - var group = this.http.group; - var controller = ''; - //检测controller名 - if (nameReg.test(this.http.controller)) { - controller = A(group + '/' + this.http.controller, this.http); - if (controller) { - return controller; - } - } - //controller不存在时调用的魔术方法 - var controllerConf = C('call_controller'); - if (controllerConf) { - if (isString(controllerConf)) { - controllerConf = controllerConf.split(':'); - } - var action = Dispatcher.getAction(controllerConf.pop()); - controller = Dispatcher.getController(controllerConf.pop()); - group = Dispatcher.getGroup(controllerConf.pop()); - controller = A(group + '/' + controller, this.http); - if (controller && isFunction(controller[action + C('action_suffix')])) { - this.http.group = group; - this.http.controller = controller; - this.http.action = action; - return controller; - } - } - }, - /** - * 执行 - * @return {[type]} [description] - */ - exec: function(){ - var controller = this.getController(); - if (!controller) { - var err = new Error('Controller `' + this.http.controller + '` not found. ' + this.http.pathname); - return getPromise(err, true); - } - var self = this; - var action = this.http.action; - var act = action; - //添加action后缀 - action += C('action_suffix') || ''; - //检测action名 - if (!nameReg.test(action)) { - return getPromise(new Error('action `' + act + '` is not valid. ' + this.http.pathname), true); - } - var initReturnPromise = getPromise(controller.__initReturn); - //对应的action方法存在 - if (isFunction(controller[action])) { - //方法参数自动绑定,直接从形参里拿到对应的值 - if (C('url_params_bind')) { - var toString = controller[action].toString().replace(commentReg, ''); - var match = toString.match(parsReg)[1].split(/,/).filter(function(item){ - return item; - }); - //匹配到形参 - if (match && match.length) { - return initReturnPromise.then(function(){ - var data = match.map(function(item){ - return self.http.post[item] || self.http.get[item] || ''; - }); - return self.execAction(controller, action, act, data); - }); - } - } - return initReturnPromise.then(function(){ - return self.execAction(controller, action, act); - }); - }else{ - //当指定的方法不存在时,调用魔术方法 - //默认为__call方法 - var callMethod = C('call_method'); - if (callMethod && isFunction(controller[callMethod])) { - return initReturnPromise.then(function(){ - return controller[callMethod](act, action); - }); - } - } - return getPromise(new Error('action `' + action + '` not found. ' + self.http.pathname), true); - }, - /** - * 执行一个action, 支持before和after的统一操作 - * 不对每个action都增加一个before和after,而是使用统一的策略 - * 默认before和after调用名__before和__after - * @param {[type]} controller [description] - * @param {[type]} action [description] - * @param {[type]} act [description] - * @param {[type]} data [description] - * @return {[type]} [description] - */ - execAction: function(controller, action, act, data){ - var promise = getPromise(); - //before action - var before = C('before_action_name'); - if (before && isFunction(controller[before])) { - promise = getPromise(controller[before](act, action)); - } - return promise.then(function(){ - if (data) { - return controller[action].apply(controller, data) - }else{ - return controller[action]() - } - }).then(function(){ - //after action - var after = C('after_action_name'); - if (after && isFunction(controller[after])) { - return controller[after](act, action); - } - }); - }, - /** - * 发送错误信息 - * @param {[type]} error [description] - * @return {[type]} [description] - */ - sendError: function(error){ - var message = isError(error) ? error.stack : error; - var http = this.http; - console.log(message); - if (!http.res) { - return; - } - if (APP_DEBUG) { - http.res.statusCode = 500; - http.res.end(message); - }else{ - http.res.statusCode = 500; - http.setHeader('Content-Type', 'text/html; charset=' + C('encoding')); - var readStream = fs.createReadStream(C('error_tpl_path')); - readStream.pipe(http.res); - readStream.on('end', function(){ - http.res.end(); - }); - } + +var App = module.exports = {}; +/** + * 根据http里的group和controller获取对应的controller实例 + * @param {[type]} http [description] + * @return {[type]} [description] + */ +App.getBaseController = function(http){ + 'use strict'; + var gc = ucfirst(http.group) + '/' + ucfirst(http.controller) + 'Controller'; + var path = getThinkRequirePath(gc); + if (path) { + return require(path)(http); + } +} +/** + * controller不存在时调用的默认controller + * @return {[type]} [description] + */ +App.getCallController = function(http){ + 'use strict'; + var config = C('call_controller'); + if (!config) { + return; + } + if (isString(config)) { + config = config.split(':'); + } + var action = Dispatcher.getAction(config.pop()); + var controller = Dispatcher.getController(config.pop()); + var group = Dispatcher.getGroup(config.pop()); + var instance = this.getBaseController({ + group: group, + controller: controller + }) + if (instance && isFunction(instance[action + C('action_suffix')])) { + http.group = group; + http.controller = controller; + http.action = action; + } + return instance; +} + +/** + * 执行具体的action,调用前置和后置操作 + * @return {[type]} [description] + */ +App.execAction = function(controller, action, data, callMethod){ + 'use strict'; + //action操作 + var act = action + C('action_suffix'); + var flag = false; + //action不存在时执行魔术方法 + if (callMethod && !isFunction(controller[act])) { + var call = C('call_method'); + if (call && isFunction(controller[call])) { + flag = true; + act = call; } - }; -}); + } + //action不存在 + if (!isFunction(controller[act])) { + return getPromise('action `' + action + '` not found. ', true); + } + var promise = getPromise(); + //action前置操作 + var before = C('before_action'); + if (before && isFunction(controller[before])) { + promise = controller[before](action); + } + promise = promise.then(function(){ + //action魔术方法只传递action参数 + if (flag) { + return controller[act](action); + } + if (data) { + return controller[act].apply(controller, data); + }else{ + return controller[act](); + } + }); + //action后置操作 + var after = C('after_action'); + if (after && isFunction(controller[after])) { + promise = promise.then(function(){ + return controller[after](action); + }) + } + return promise; +} + +/** + * 获取action的形参 + * @return {[type]} [description] + */ +App.getActionParams = function(fn, http){ + 'use strict'; + var toString = fn.toString().replace(commentReg, ''); + var match = toString.match(parsReg)[1].split(/\s*,\s*/); + //匹配到形参 + var params; + if (match && match.length) { + params = match.map(function(item){ + return http.post[item] || http.get[item] || ''; + }); + } + return params; +} +/** + * 执行 + * @param {[type]} http [description] + * @return {[type]} [description] + */ +App.exec = function(http){ + 'use strict'; + var controller = this.getBaseController(http) || this.getCallController(http); + //controller不存在 + if (!controller) { + var err = new Error('Controller `' + http.controller + '` not found. ' + http.pathname); + return getPromise(err, true); + } + var params; + var actionFn = controller[http.action + C('action_suffix')]; + //参数绑定 + if (C('url_params_bind') && isFunction(actionFn)) { + params = this.getActionParams(actionFn, http); + } + var promise = getPromise(controller.__initReturn); + var self = this; + return promise.then(function(){ + return self.execAction(controller, http.action, params, true); + }) +} +/** + * 发送错误信息 + * @param {[type]} error [description] + * @return {[type]} [description] + */ +App.sendError = function(http, error){ + 'use strict'; + var message = isError(error) ? error.stack : error; + console.log(message); + if (!http.res) { + return; + } + if (APP_DEBUG) { + http.res.statusCode = 500; + http.res.end(message); + }else{ + http.res.statusCode = 500; + http.setHeader('Content-Type', 'text/html; charset=' + C('encoding')); + var readStream = fs.createReadStream(C('error_tpl_path')); + readStream.pipe(http.res); + readStream.on('end', function(){ + http.res.end(); + }); + } +} /** * run @@ -254,26 +251,25 @@ App.listener = function(http){ http.res.end(); return getDefer().promise; } - var instance = App(http); var domainInstance = domain.create(); var deferred = getDefer(); domainInstance.on('error', function(err){ - instance.sendError(err); + App.sendError(http, err); deferred.reject(err); }); domainInstance.run(function(){ return tag('app_init', http).then(function(){ - return instance.dispatch(); + return Dispatcher(http).run(); }).then(function(){ return tag('app_begin', http); }).then(function(){ return tag('action_init', http); }).then(function(){ - return instance.exec(); + return App.exec(http); }).then(function(){ return tag('app_end', http); }).catch(function(err){ - instance.sendError(err); + App.sendError(http, err); }).then(function(){ deferred.resolve(); }) diff --git a/lib/Lib/Core/Dispatcher.js b/lib/Lib/Core/Dispatcher.js index 15e919be..d5213d6c 100644 --- a/lib/Lib/Core/Dispatcher.js +++ b/lib/Lib/Core/Dispatcher.js @@ -80,7 +80,6 @@ var Dispatcher = module.exports = Class(function(){ } }; }); - /** * 获取group * @param {[type]} group [description] @@ -91,6 +90,12 @@ Dispatcher.getGroup = function(group){ group = group || C('default_group'); return ucfirst(group); }; + +/** + * 检测Controller和Action是否合法的正则 + * @type {RegExp} + */ +var nameReg = /^[A-Za-z\_](\w)*$/; /** * 获取controller * @param {[type]} controller [description] @@ -98,7 +103,9 @@ Dispatcher.getGroup = function(group){ */ Dispatcher.getController = function(controller){ 'use strict'; - controller = controller || C('default_controller'); + if (!controller || !nameReg.test(controller)) { + return ucfirst(C('default_controller')); + } return ucfirst(controller); }; /** @@ -108,6 +115,8 @@ Dispatcher.getController = function(controller){ */ Dispatcher.getAction = function(action){ 'use strict'; - action = action || C('default_action'); + if (!action || !nameReg.test(action)) { + return C('default_action'); + } return action; }; \ No newline at end of file