diff --git a/application/admin/controller/setting/SystemGroupData.php b/application/admin/controller/setting/SystemGroupData.php
index ed319378..f8f93628 100644
--- a/application/admin/controller/setting/SystemGroupData.php
+++ b/application/admin/controller/setting/SystemGroupData.php
@@ -109,7 +109,8 @@ class SystemGroupData extends AuthController
foreach ($params as $key => $param) {
foreach ($Fields['fields'] as $index => $field) {
if($key == $field["title"]){
- if($param == "" || count($param) == 0)
+// if($param == "" || count($param) == 0)
+ if($param == "")
return Json::fail($field["name"]."不能为空!");
else{
$value[$key]["type"] = $field["type"];
diff --git a/application/admin/controller/store/StoreCategory.php b/application/admin/controller/store/StoreCategory.php
index 71d72375..782f7eb7 100644
--- a/application/admin/controller/store/StoreCategory.php
+++ b/application/admin/controller/store/StoreCategory.php
@@ -1,5 +1,4 @@
$menu['id'],'label'=>$menu['html'].$menu['cate_name'],'disabled'=>$menu['pid']== 0];//,'disabled'=>$menu['pid']== 0];
}
return $menus;
- })->filterable(1)->multiple(1),
- Form::input('store_name','产品名称')->col(Form::col(24)),
+ })->filterable(1)->multiple(1)->required(),
+ Form::input('store_name','产品名称')->col(Form::col(24))->validateFn(function($validate){
+ $validate->min(5)->max(32);
+ })->required(),
Form::input('store_info','产品简介')->type('textarea'),
Form::input('keyword','产品关键字')->placeholder('多个用英文状态下的逗号隔开'),
- Form::input('unit_name','产品单位','件'),
- Form::frameImageOne('image','产品主图片(305*305px)',Url::build('admin/widget.images/index',array('fodder'=>'image')))->icon('image')->width('100%')->height('500px'),
- Form::frameImages('slider_image','产品轮播图(640*640px)',Url::build('admin/widget.images/index',array('fodder'=>'slider_image')))->maxLength(5)->icon('images')->width('100%')->height('500px')->spin(0),
- Form::number('price','产品售价')->min(0)->col(8),
+ Form::input('unit_name','产品单位','件')->required(),
+ Form::frameImageOne('image','产品主图片(305*305px)',Url::build('admin/widget.images/index',array('fodder'=>'image')))->icon('image')->width('100%')->height('500px')->required(),
+ Form::frameImages('slider_image','产品轮播图(640*640px)',Url::build('admin/widget.images/index',array('fodder'=>'slider_image')))->maxLength(5)->icon('images')->width('100%')->height('500px')->spin(0)
+ ->required()->validateFn(function($validate){
+ $validate->min(1)->max(5);
+ }),
+ Form::number('price','产品售价')->min(0)->col(8)->required(),
Form::number('ot_price','产品市场价')->min(0)->col(8),
Form::number('give_integral','赠送积分')->min(0)->precision(0)->col(8),
- Form::number('postage','邮费')->min(0)->col(Form::col(8)),
+ Form::number('postage','邮费')->min(0)->col(Form::col(8))->required(),
Form::number('sales','销量',0)->min(0)->precision(0)->col(8)->readonly(1),
Form::number('ficti','虚拟销量')->min(0)->precision(0)->col(8),
- Form::number('stock','库存')->min(0)->precision(0)->col(8),
+ Form::number('stock','库存')->min(0)->precision(0)->col(8)->required(),
Form::number('cost','产品成本价')->min(0)->col(8),
- Form::number('sort','排序')->col(8),
+ Form::number('sort','排序',0)->col(8)->required(),
Form::radio('is_show','产品状态',0)->options([['label'=>'上架','value'=>1],['label'=>'下架','value'=>0]])->col(8),
Form::radio('is_hot','热卖单品',0)->options([['label'=>'是','value'=>1],['label'=>'否','value'=>0]])->col(8),
Form::radio('is_benefit','促销单品',0)->options([['label'=>'是','value'=>1],['label'=>'否','value'=>0]])->col(8),
diff --git a/application/admin/controller/system/SystemFile.php b/application/admin/controller/system/SystemFile.php
index 87eb8417..09234cdc 100644
--- a/application/admin/controller/system/SystemFile.php
+++ b/application/admin/controller/system/SystemFile.php
@@ -20,11 +20,11 @@ class SystemFile extends AuthController
public function opendir($filedir=''){
$fileAll = array('dir'=>[],'file'=>[]);
if(Request::instance()->param('superior') && !empty(Request::instance()->param('dir'))){
- $path = '.'.DS.Request::instance()->param('dir');
+ $path = './'.Request::instance()->param('dir');
$path = dirname($path);
}else{
$path = !empty(Request::instance()->param('dir'))?Request::instance()->param('dir'):'.';
- $path = $path.DS.Request::instance()->param('filedir');
+ $path = $path.'/'.Request::instance()->param('filedir');
}
$list = scandir($path);
foreach($list as $key=>$v) {
@@ -38,6 +38,9 @@ class SystemFile extends AuthController
}
}
// var_dump($fileAll['file']);
+ //兼容windows
+ $uname=php_uname('s');
+ if(strstr($uname,'Windows')!==false) $path = ltrim($path,'\\');
$dir = ltrim($path,'./');
$this->assign(compact('fileAll','dir'));
return $this->fetch();
@@ -65,6 +68,10 @@ class SystemFile extends AuthController
$comment = $this->request->post('comment');
$filepath = $this->request->post('filepath');
if(!empty($comment) && !empty($filepath)){
+ //兼容windows
+ $uname=php_uname('s');
+ if(strstr($uname,'Windows')!==false)
+ $filepath = ltrim(str_replace('/', DS, $filepath),'.');
$res = FileClass::write_file($filepath,$comment);
if($res){
return Json::successful('保存成功!');
diff --git a/application/admin/controller/ump/StoreCoupon.php b/application/admin/controller/ump/StoreCoupon.php
index dc6a847e..a0c4aa9b 100644
--- a/application/admin/controller/ump/StoreCoupon.php
+++ b/application/admin/controller/ump/StoreCoupon.php
@@ -42,7 +42,7 @@ class StoreCoupon extends AuthController
public function create()
{
$f = array();
- $f[] = Form::input('title','优惠券名称');
+ $f[] = Form::input('title','优惠券名称')->required();
$f[] = Form::number('coupon_price','优惠券面值',0)->min(0);
$f[] = Form::number('use_min_price','优惠券最低消费')->min(0);
$f[] = Form::number('coupon_time','优惠券有效期限')->min(0);
diff --git a/application/admin/controller/ump/StoreSeckill.php b/application/admin/controller/ump/StoreSeckill.php
index 0e58be25..71e5605d 100644
--- a/application/admin/controller/ump/StoreSeckill.php
+++ b/application/admin/controller/ump/StoreSeckill.php
@@ -75,13 +75,13 @@ class StoreSeckill extends AuthController
public function create()
{
$f = array();
- $f[] = Form::input('title','产品标题');
- $f[] = Form::input('info','秒杀活动简介')->type('textarea');
- $f[] = Form::input('unit_name','单位')->placeholder('个、位');
- $f[] = Form::dateTimeRange('section_time','活动时间');
- $f[] = Form::frameImageOne('image','产品主图片(305*305px)',Url::build('admin/widget.images/index',array('fodder'=>'image')))->icon('image');
- $f[] = Form::frameImages('images','产品轮播图(640*640px)',Url::build('admin/widget.images/index',array('fodder'=>'images')))->maxLength(5)->icon('images');
- $f[] = Form::number('price','秒杀价')->min(0)->col(12);
+ $f[] = Form::input('title','产品标题')->required();
+ $f[] = Form::input('info','秒杀活动简介')->type('textarea')->required();
+ $f[] = Form::input('unit_name','单位')->placeholder('个、位')->required();
+ $f[] = Form::dateTimeRange('section_time','活动时间')->required();
+ $f[] = Form::frameImageOne('image','产品主图片(305*305px)',Url::build('admin/widget.images/index',array('fodder'=>'image')))->icon('image')->required();
+ $f[] = Form::frameImages('images','产品轮播图(640*640px)',Url::build('admin/widget.images/index',array('fodder'=>'images')))->maxLength(5)->icon('images')->required();
+ $f[] = Form::number('price','秒杀价')->min(0)->col(12)->required();
$f[] = Form::number('ot_price','原价')->min(0)->col(12);
$f[] = Form::number('cost','成本价')->min(0)->col(12);
$f[] = Form::number('stock','库存')->min(0)->precision(0)->col(12);
@@ -93,7 +93,7 @@ class StoreSeckill extends AuthController
$f[] = Form::radio('is_postage','是否包邮',1)->options([['label'=>'是','value'=>1],['label'=>'否','value'=>0]])->col(12);
$f[] = Form::radio('is_hot','热门推荐',1)->options([['label'=>'开启','value'=>1],['label'=>'关闭','value'=>0]])->col(12);
$f[] = Form::radio('status','活动状态',1)->options([['label'=>'开启','value'=>1],['label'=>'关闭','value'=>0]])->col(12);
- $form = Form::make_post_form('添加用户通知',$f,Url::build('save'));
+ $form = Form::make_post_form('开启秒杀',$f,Url::build('save'));
$this->assign(compact('form'));
return $this->fetch('public/form-builder');
}
diff --git a/application/admin/model/order/StoreOrder.php b/application/admin/model/order/StoreOrder.php
index bfbd1214..f4d76783 100644
--- a/application/admin/model/order/StoreOrder.php
+++ b/application/admin/model/order/StoreOrder.php
@@ -54,6 +54,7 @@ class StoreOrder extends ModelBasic
$_info[$k]['cart_info'] = json_decode($v['cart_info'],true);
}
$item['_info'] = $_info;
+ $item['add_time'] = date('Y-m-d H:i:s',$item['add_time']);
if($item['pink_id'] && $item['combination_id']){
$pinkStatus = StorePink::where('order_id_key',$item['id'])->value('status');
switch ($pinkStatus){
@@ -904,4 +905,21 @@ HTML;
if(!$uid) return 0;
return self::where('uid',$uid)->where('paid',1)->where('refund_status',0)->where('status',2)->count();
}
+ /**
+ * 获取已支付的订单
+ * @param int $is_promoter
+ * @return int|string
+ */
+ public static function getOrderPayCount($is_promoter = 0){
+ return self::where('o.paid',1)->alias('o')->join('User u','u.uid=o.uid')->where('u.is_promoter',$is_promoter)->count();
+ }
+
+ /**
+ * 获取最后一个月已支付的订单
+ * @param int $is_promoter
+ * @return int|string
+ */
+ public static function getOrderPayMonthCount($is_promoter = 0){
+ return self::where('o.paid',1)->alias('o')->whereTime('o.pay_time','last month')->join('User u','u.uid=o.uid')->where('u.is_promoter',$is_promoter)->count();
+ }
}
\ No newline at end of file
diff --git a/application/admin/model/store/StoreCategory.php b/application/admin/model/store/StoreCategory.php
index 4b16e1cf..7a4e13e2 100644
--- a/application/admin/model/store/StoreCategory.php
+++ b/application/admin/model/store/StoreCategory.php
@@ -7,7 +7,6 @@
namespace app\admin\model\store;
-
use traits\ModelTrait;
use basic\ModelBasic;
use service\UtilService;
@@ -20,16 +19,39 @@ class StoreCategory extends ModelBasic
{
use ModelTrait;
+ /*
+ * 异步获取分类列表
+ * @param $where
+ * @return array
+ */
+ public static function CategoryList($where){
+ $data=($data=self::systemPage($where,true)->page((int)$where['page'],(int)$where['limit'])->select()) && count($data) ? $data->toArray() :[];
+ foreach ($data as &$item){
+ if($item['pid']){
+ $item['pid_name'] = self::where('id',$item['pid'])->value('cate_name');
+ }else{
+ $item['pid_name'] = '顶级';
+ }
+ }
+ $count=self::systemPage($where,true)->count();
+ return compact('count','data');
+ }
/**
* @param $where
* @return array
*/
- public static function systemPage($where){
+ public static function systemPage($where,$isAjax=false){
$model = new self;
if($where['pid'] != '') $model = $model->where('pid',$where['pid']);
else if($where['pid']=='' && $where['cate_name']=='') $model = $model->where('pid',0);
if($where['is_show'] != '') $model = $model->where('is_show',$where['is_show']);
if($where['cate_name'] != '') $model = $model->where('cate_name','LIKE',"%$where[cate_name]%");
+ if($isAjax===true){
+ if(isset($where['order']) && $where['order']!=''){
+ $model=$model->order(self::setOrder($where['order']));
+ }
+ return $model;
+ }
return self::page($model,function ($item){
if($item['pid']){
$item['pid_name'] = self::where('id',$item['pid'])->value('cate_name');
diff --git a/application/admin/model/store/StoreProductAttr.php b/application/admin/model/store/StoreProductAttr.php
index d685496b..910cb945 100644
--- a/application/admin/model/store/StoreProductAttr.php
+++ b/application/admin/model/store/StoreProductAttr.php
@@ -77,7 +77,7 @@ class StoreProductAttr extends ModelBasic
];
}
foreach ($valueList as $k=>$value){
- ksort($value['detail'],SORT_STRING);
+ sort($value['detail'],SORT_STRING);
$suk = implode(',',$value['detail']);
$valueGroup[$suk] = [
'product_id'=>$productId,
diff --git a/application/admin/view/order/store_order/index.php b/application/admin/view/order/store_order/index.php
index f06384ba..04c64692 100644
--- a/application/admin/view/order/store_order/index.php
+++ b/application/admin/view/order/store_order/index.php
@@ -82,7 +82,7 @@
{switch name='type'}
{case value="1"}
-
+
{/case}
{case value="2"}
@@ -175,15 +175,15 @@
case 2:
join=[
{type:'checkbox'},
- {field: 'id', title: 'ID', sort: true,event:'id',width:'5%'},
- {field: 'image', title: '产品图片',templet:'#image'},
+ {field: 'id', title: 'ID', sort: true,event:'id',width:'6%'},
+ {field: 'image', title: '产品图片',templet:'#image',width:'10%'},
{field: 'store_name', title: '产品名称',templet:'#store_name'},
- {field: 'price', title: '产品价格',edit:'price'},
- {field: 'ficti', title: '虚拟销量',edit:'ficti'},
- {field: 'stock', title: '库存',edit:'stock'},
- {field: 'sort', title: '排序',edit:'sort'},
- {field: 'sales', title: '销量',sort: true,event:'sales'},
- {field: 'status', title: '状态',templet:"#checkboxstatus"},
+ {field: 'price', title: '价格',edit:'price',width:'8%'},
+ {field: 'ficti', title: '虚拟销量',edit:'ficti',width:'8%'},
+ {field: 'stock', title: '库存',edit:'stock',width:'6%'},
+ {field: 'sort', title: '排序',edit:'sort',width:'6%'},
+ {field: 'sales', title: '销量',sort: true,event:'sales',width:'6%'},
+ {field: 'status', title: '状态',templet:"#checkboxstatus",width:'8%'},
{field: 'right', title: '操作',align:'center',toolbar:'#act',width:'14%'},
];
break;
diff --git a/application/admin/view/ump/store_combination/index.php b/application/admin/view/ump/store_combination/index.php
index a89434de..f6816156 100644
--- a/application/admin/view/ump/store_combination/index.php
+++ b/application/admin/view/ump/store_combination/index.php
@@ -135,8 +135,8 @@
layList.tableList('combinationList',"{:Url('get_combination_list')}",function () {
return [
{field: 'id', title: '编号', sort: true,event:'id'},
- {field: 'image', title: '拼团图片',templet: '

'},
- {field: 'title', title: '拼团名称'},
+ {field: 'image', title: '拼团图片',width:'10%',templet: '

'},
+ {field: 'title', title: '拼团名称',width:'10%'},
{field: 'ot_price', title: '原价'},
{field: 'price', title: '拼团价'},
{field: 'stock', title: '库存'},
diff --git a/application/admin/view/ump/store_seckill/index.php b/application/admin/view/ump/store_seckill/index.php
index fc39be2a..5888cef4 100644
--- a/application/admin/view/ump/store_seckill/index.php
+++ b/application/admin/view/ump/store_seckill/index.php
@@ -113,17 +113,17 @@
layList.form.render();
layList.tableList('seckillList',"{:Url('get_seckill_list')}",function () {
return [
- {field: 'id', title: '编号', sort: true,width:'5%',event:'id',unresize:true},
- {field: 'image', title: '产品图片',unresize:true, width: '8%',templet: '

'},
- {field: 'title', title: '活动标题',width:'14%',unresize:true},
- {field: 'info', title: '活动简介',width:'17%',unresize:true},
- {field: 'ot_price', title: '原价',width:'6%',unresize:true},
- {field: 'price', title: '秒杀价',unresize:true,width:'6%'},
- {field: 'stock', title: '库存',width:'7%',unresize:true},
- {field: 'start_name', title: '秒杀状态',width:'13%',toolbar:"#statusCn",unresize:true},
- {field: 'stop_time', title: '结束时间', width: '13%',toolbar: '#stopTime',unresize:true},
- {field: 'status', title: '状态',width:'6%',toolbar:"#status",unresize:true},
- {field: 'right', title: '操作', width: '5%', align: 'center', toolbar: '#barDemo',unresize:true}
+ {field: 'id', title: 'ID', sort: true,width:'6%',event:'id'},
+ {field: 'image', title: '产品图片', width: '10%',templet: '

'},
+ {field: 'title', title: '活动标题'},
+ {field: 'info', title: '活动简介',width:'20%'},
+ {field: 'ot_price', title: '原价',width:'6%'},
+ {field: 'price', title: '秒杀价',width:'6%'},
+ {field: 'stock', title: '库存',width:'6%'},
+ {field: 'start_name', title: '秒杀状态',width:'8%',toolbar:"#statusCn"},
+ {field: 'stop_time', title: '结束时间', width: '13%',toolbar: '#stopTime'},
+ {field: 'status', title: '状态',width:'6%',toolbar:"#status"},
+ {field: 'right', title: '操作', width: '6%', align: 'center', toolbar: '#barDemo'}
]
});
layList.tool(function (event,data,obj) {
diff --git a/application/admin/view/ump/user_point/index.php b/application/admin/view/ump/user_point/index.php
index 1a7c87b3..dc0b8607 100644
--- a/application/admin/view/ump/user_point/index.php
+++ b/application/admin/view/ump/user_point/index.php
@@ -88,7 +88,7 @@
layList.form.render();
layList.tableList('userList',"{:Url('getponitlist')}",function () {
return [
- {field: 'id', title: '编号', sort: true,event:'uid'},
+ {field: 'id', title: 'ID', sort: true,event:'uid',width:'8%'},
{field: 'title', title: '标题' },
{field: 'balance', title: '积分余量',sort:true,event:'now_money'},
{field: 'number', title: '明细数字',sort:true},
diff --git a/application/admin/view/wechat/reply/keyword.php b/application/admin/view/wechat/reply/keyword.php
index b2b50c8d..73ca5e03 100644
--- a/application/admin/view/wechat/reply/keyword.php
+++ b/application/admin/view/wechat/reply/keyword.php
@@ -64,7 +64,7 @@
{/switch}
-
+ |
diff --git a/application/wap/model/store/StoreCart.php b/application/wap/model/store/StoreCart.php
index 2cb52f6c..6cc90684 100644
--- a/application/wap/model/store/StoreCart.php
+++ b/application/wap/model/store/StoreCart.php
@@ -99,14 +99,15 @@ class StoreCart extends ModelBasic
foreach ($list as $k=>$cart) {
if ($cart['seckill_id']) {
$product = StoreSeckill::field($seckillInfoField)
- ->find($cart['seckill_id'])->toArray();
+ ->find($cart['seckill_id']);
}elseif($cart['bargain_id']){
$product = StoreBargain::field($bargainInfoField)
- ->find($cart['bargain_id'])->toArray();
+ ->find($cart['bargain_id']);
}else{
$product = StoreProduct::field($productInfoField)
- ->find($cart['product_id'])->toArray();
+ ->find($cart['product_id']);
}
+ if(!empty($product)) $product = $product->toArray();
$cart['productInfo'] = $product;
//商品不存在
if (!$product) {
diff --git a/extend/service/WechatService.php b/extend/service/WechatService.php
index a18875db..347c069f 100644
--- a/extend/service/WechatService.php
+++ b/extend/service/WechatService.php
@@ -27,25 +27,24 @@ class WechatService
{
private static $instance = null;
- /**获取微信配置参数
- * @return array
- */
public static function options()
{
- $wechat = SystemConfigService::more(['wechat_appid','wechat_appsecret','wechat_token']);
+ $wechat = SystemConfigService::more(['wechat_appid','wechat_appsecret','wechat_token','wechat_encodingaeskey','wechat_encode']);
$payment = SystemConfigService::more(['pay_weixin_mchid','pay_weixin_client_cert','pay_weixin_client_key','pay_weixin_key','pay_weixin_open']);
$config = [
- 'app_id'=>isset($wechat['wechat_appid']) ? trim($wechat['wechat_appid']):'',
- 'secret'=>isset($wechat['wechat_appsecret']) ? trim($wechat['wechat_appsecret']):'',
- 'token'=>isset($wechat['wechat_token']) ? trim($wechat['wechat_token']):'',
+ 'app_id'=>isset($wechat['wechat_appid']) ? $wechat['wechat_appid']:'',
+ 'secret'=>isset($wechat['wechat_appsecret']) ? $wechat['wechat_appsecret']:'',
+ 'token'=>isset($wechat['wechat_token']) ? $wechat['wechat_token']:'',
'guzzle' => [
'timeout' => 10.0, // 超时时间(秒)
],
];
+ if((int)$wechat['wechat_encode']>0 && isset($wechat['wechat_encodingaeskey']) && !empty($wechat['wechat_encodingaeskey']))
+ $config['aes_key'] = $wechat['wechat_encodingaeskey'];
if(isset($payment['pay_weixin_open']) && $payment['pay_weixin_open'] == 1){
$config['payment'] = [
- 'merchant_id'=>trim($payment['pay_weixin_mchid']),
- 'key'=>trim($payment['pay_weixin_key']),
+ 'merchant_id'=>$payment['pay_weixin_mchid'],
+ 'key'=>$payment['pay_weixin_key'],
'cert_path'=>realpath('.'.$payment['pay_weixin_client_cert']),
'key_path'=>realpath('.'.$payment['pay_weixin_client_key']),
'notify_url'=>SystemConfigService::get('site_url').Url::build('wap/Wechat/notify')
@@ -62,9 +61,6 @@ class WechatService
return self::$instance;
}
- /**
- * 微信接口
- */
public static function serve()
{
$wechat = self::application(true);
@@ -133,6 +129,7 @@ class WechatService
$response = HookService::resultListen('wechat_message_other',$message,null,true,$behavior);
break;
}
+
return $response;
});
}
@@ -370,11 +367,6 @@ class WechatService
return self::paymentService()->refund($orderNo,$refundNo,$totalFee,$refundFee,$opUserId,$type,$refundAccount,$refundReason);
}
- /**订单退款
- * @param $orderNo
- * @param array $opt
- * @return bool
- */
public static function payOrderRefund($orderNo, array $opt)
{
if(!isset($opt['pay_price'])) exception('缺少pay_price');
@@ -420,10 +412,6 @@ class WechatService
return self::application()->js;
}
- /** jsSdk
- * @param string $url
- * @return array|string
- */
public static function jsSdk($url = '')
{
$apiList = ['onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone', 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'onVoicePlayEnd', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'translateVoice', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard'];
diff --git a/public/system/css/layui-admin.css b/public/system/css/layui-admin.css
index 564b9d60..efe36ee9 100644
--- a/public/system/css/layui-admin.css
+++ b/public/system/css/layui-admin.css
@@ -1,4 +1,11 @@
@charset "UTF-8";
+.layui-btn {
+ background-color: #0092DC;
+}
+.layui-btn-primary:hover {
+ border-color: #0092DC;
+ color: #333;
+}
.layui-table-box{
overflow: initial;
}
@@ -11,44 +18,14 @@
.table-responsive{
overflow: initial;
}
-.layui-table img{width: 100% !important;}
-/*
-部分样式重构
- */
-.layui-form-pane .layui-input, .layui-select, .layui-textarea {
- height: 32px;
- line-height: 1.5;
- padding: 4px 7px;
- font-size: 12px;
- border: 1px solid #dddee1;
- color: #495060;
- background-color: #fff;
+/*.layui-table img{width: 100% !important;}*/
+/*部分样式重构*/
+.layui-laypage-limits select{
+ height: 26px;
}
.layui-card-body {
}
-.layui-form-pane{
- /*padding: 20px;*/
-}
-.layui-form-pane .layui-form-label {
- padding: 5px 15px;
- height: 32px;
-}
-.layui-fluid {
- padding: 0;
-}
-.layui-btn-normal{
- background-color:#0092DC;
-}
-.layui-btn .layui-icon {
- font-size: 12px;
-}
-.layui-btn-sm i {
- font-size: 12px!important;
-}
-.layui-form-onswitch {
- border-color: #0092DC;
- background-color: #0092DC;
-}
+
.layui-table-cell p{
height: 20px;
line-height: 20px;
@@ -58,6 +35,10 @@
width: 14px;
height: 14px;
}
+
+.layui-laypage a, .layui-laypage button, .layui-laypage input, .layui-laypage select, .layui-laypage span {
+ color:#333 !important;
+}
.layui-form-checked[lay-skin=primary] i {
border-color: #0093DE;
background-color: #0093DE;
@@ -73,23 +54,6 @@
.layui-tab-title .layui-this:after{
border-bottom: 2px solid #0092DC !important;
}
-.layui-form-label{
- width: auto;
-}
-.layui-table-cell {
- white-space:normal;
- height: auto!important;
-}
-.layui-input-block .layui-admin-input{
- width: 50%;
- height: 34px;
-}
-.layui-form-item{
- margin-bottom: 0;
-}
-.layui-input-block .time-w{
- width: 200px;
-}
.layui-btn-group button i{
line-height: 30px;
@@ -99,11 +63,8 @@
.back-f8{
background-color: #F8F8F8;
}
-.layui-input-block button{
- border: 1px solid #C9C9C9;
-}
.layui-card-body p.layuiadmin-big-font {
- font-size: 36px;
+ font-size: 24px;
color: #666;
line-height: 36px;
padding: 5px 0 10px;
@@ -184,3 +145,92 @@
.layadmin-text-center{
text-align: center;
}
+/*表格样式*/
+.layui-table-view .layui-table td, .layui-table-view .layui-table th {
+ font-size: 13px;
+ font-weight: bolder;
+}
+.layui-table-cell {
+ white-space:normal;
+ height: auto!important;
+ font-size: 13px;
+ font-weight: normal;
+}
+/*form 样式*/
+
+.layui-form-select .layui-input {
+ padding-right: 30px;
+ cursor: pointer;
+ font-size: 12px;
+ height: 32px;
+}
+.layui-form-select dl {
+ top: 32px;
+ font-size: 12px;
+}
+.layui-form-select dl dd.layui-this {
+ background-color: #0092DC;
+ color: #fff;
+}
+.layui-input{
+ height: 32px;
+ font-size: 12px;
+}
+.layui-input-block .layui-admin-input{
+ width: 50%;
+ font-size: 12px;
+ height: 32px;
+}
+.layui-form-item{
+ margin-bottom: 0;
+}
+.layui-input-block .time-w{
+ width: 200px;
+}
+.layui-form-pane .layui-input, .layui-select, .layui-textarea {
+ height: 34px;
+ line-height: 1.5;
+ padding: 4px 12px;
+ font-size: 12px;
+ border: 1px solid #e5e6e7;
+ color: #333;
+ background-color: #fff;
+}
+.layui-form-pane{
+ /*padding: 20px;*/
+}
+.layui-form-pane .layui-inline .layui-form-label {
+ padding: 5px 15px;
+ height: 34px;
+ line-height: 24px;
+ background: none;
+ border-radius: 5px 0 0 5px;
+}
+.layui-form-item .layui-btn{
+ margin-top: -5px;
+}
+.layui-form-label{
+ width: auto;
+ padding: 6px;
+}
+.layui-fluid {
+ padding: 0;
+}
+.layui-btn-normal{
+ background-color:#0092DC;
+}
+.layui-btn .layui-icon {
+ font-size: 12px;
+}
+.layui-btn-sm i {
+ font-size: 12px!important;
+}
+.layui-form-onswitch {
+ border-color: #0092DC;
+ background-color: #0092DC;
+}
+.layui-btn-primary {
+ border: 1px solid #e5e6e7;
+ background-color: #fff;
+ color: #333;
+}
\ No newline at end of file
diff --git a/thinkphp/library/think/db/Builder.php b/thinkphp/library/think/db/Builder.php
index 213cb090..1a865a9d 100644
--- a/thinkphp/library/think/db/Builder.php
+++ b/thinkphp/library/think/db/Builder.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
@@ -11,7 +11,6 @@
namespace think\db;
-use BadMethodCallException;
use PDO;
use think\Exception;
@@ -26,7 +25,7 @@ abstract class Builder
protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME'];
// SQL表达式
- protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';
+ protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT%%LOCK%%COMMENT%';
protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
protected $updateSql = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
@@ -99,8 +98,11 @@ abstract class Builder
$result = [];
foreach ($data as $key => $val) {
- $item = $this->parseKey($key, $options);
- if (is_object($val) && method_exists($val, '__toString')) {
+ $item = $this->parseKey($key, $options, true);
+ if ($val instanceof Expression) {
+ $result[$item] = $val->getValue();
+ continue;
+ } elseif (is_object($val) && method_exists($val, '__toString')) {
// 对象数据写入
$val = $val->__toString();
}
@@ -110,8 +112,25 @@ abstract class Builder
}
} elseif (is_null($val)) {
$result[$item] = 'NULL';
- } elseif (isset($val[0]) && 'exp' == $val[0]) {
- $result[$item] = $val[1];
+ } elseif (is_array($val) && !empty($val)) {
+ switch (strtolower($val[0])) {
+ case 'inc':
+// $result[$item] = $item . '+' . floatval($val[1]);
+ if ($key == $val[1]) {
+ $result[$item] = $this->parseKey($val[1]) . '+' . floatval($val[2]);
+ }
+
+ break;
+ case 'dec':
+// $result[$item] = $item . '-' . floatval($val[1]);
+ if ($key == $val[1]) {
+ $result[$item] = $this->parseKey($val[1]) . '-' . floatval($val[2]);
+ }
+
+ break;
+ case 'exp':
+ throw new Exception('not support data:[' . $val[0] . ']');
+ }
} elseif (is_scalar($val)) {
// 过滤非标量数据
if (0 === strpos($val, ':') && $this->query->isBind(substr($val, 1))) {
@@ -133,7 +152,7 @@ abstract class Builder
* @param array $options
* @return string
*/
- protected function parseKey($key, $options = [])
+ protected function parseKey($key, $options = [], $strict = false)
{
return $key;
}
@@ -174,8 +193,10 @@ abstract class Builder
// 支持 'field1'=>'field2' 这样的字段别名定义
$array = [];
foreach ($fields as $key => $field) {
- if (!is_numeric($key)) {
- $array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options);
+ if ($field instanceof Expression) {
+ $array[] = $field->getValue();
+ } elseif (!is_numeric($key)) {
+ $array[] = $this->parseKey($key, $options) . ' AS ' . $this->parseKey($field, $options, true);
} else {
$array[] = $this->parseKey($field, $options);
}
@@ -197,9 +218,6 @@ abstract class Builder
$item = [];
foreach ((array) $tables as $key => $table) {
if (!is_numeric($key)) {
- if (strpos($key, '@think')) {
- $key = strstr($key, '@think', true);
- }
$key = $this->parseSqlTable($key);
$item[] = $this->parseKey($key) . ' ' . (isset($options['alias'][$table]) ? $this->parseKey($options['alias'][$table]) : $this->parseKey($table));
} else {
@@ -257,7 +275,9 @@ abstract class Builder
foreach ($where as $key => $val) {
$str = [];
foreach ($val as $field => $value) {
- if ($value instanceof \Closure) {
+ if ($value instanceof Expression) {
+ $str[] = ' ' . $key . ' ( ' . $value->getValue() . ' )';
+ } elseif ($value instanceof \Closure) {
// 使用闭包查询
$query = new Query($this->connection);
call_user_func_array($value, [ & $query]);
@@ -298,7 +318,7 @@ abstract class Builder
protected function parseWhereItem($field, $val, $rule = '', $options = [], $binds = [], $bindName = null)
{
// 字段分析
- $key = $field ? $this->parseKey($field, $options) : '';
+ $key = $field ? $this->parseKey($field, $options, true) : '';
// 查询规则和条件
if (!is_array($val)) {
@@ -331,13 +351,15 @@ abstract class Builder
throw new Exception('where express error:' . $exp);
}
}
- $bindName = $bindName ?: 'where_' . str_replace(['.', '-'], '_', $field);
+ $bindName = $bindName ?: 'where_' . $rule . '_' . str_replace(['.', '-'], '_', $field);
if (preg_match('/\W/', $bindName)) {
// 处理带非单词字符的字段名
$bindName = md5($bindName);
}
- if (is_object($value) && method_exists($value, '__toString')) {
+ if ($value instanceof Expression) {
+
+ } elseif (is_object($value) && method_exists($value, '__toString')) {
// 对象数据写入
$value = $value->__toString();
}
@@ -374,7 +396,11 @@ abstract class Builder
}
} elseif ('EXP' == $exp) {
// 表达式查询
- $whereStr .= '( ' . $key . ' ' . $value . ' )';
+ if ($value instanceof Expression) {
+ $whereStr .= '( ' . $key . ' ' . $value->getValue() . ' )';
+ } else {
+ throw new Exception('where express error:' . $exp);
+ }
} elseif (in_array($exp, ['NOT NULL', 'NULL'])) {
// NULL 查询
$whereStr .= $key . ' IS ' . $exp;
@@ -492,6 +518,11 @@ abstract class Builder
}
}
$bindName = $bindName ?: $key;
+
+ if ($this->query->isBind($bindName)) {
+ $bindName .= '_' . str_replace('.', '_', uniqid('', true));
+ }
+
$this->query->bind($bindName, $value, $bindType);
return ':' . $bindName;
}
@@ -522,7 +553,9 @@ abstract class Builder
list($table, $type, $on) = $item;
$condition = [];
foreach ((array) $on as $val) {
- if (strpos($val, '=')) {
+ if ($val instanceof Expression) {
+ $condition[] = $val->getValue();
+ } elseif (strpos($val, '=')) {
list($val1, $val2) = explode('=', $val, 2);
$condition[] = $this->parseKey($val1, $options) . '=' . $this->parseKey($val2, $options);
} else {
@@ -546,28 +579,29 @@ abstract class Builder
*/
protected function parseOrder($order, $options = [])
{
- if (is_array($order)) {
- $array = [];
- foreach ($order as $key => $val) {
- if (is_numeric($key)) {
- if ('[rand]' == $val) {
- if (method_exists($this, 'parseRand')) {
- $array[] = $this->parseRand();
- } else {
- throw new BadMethodCallException('method not exists:' . get_class($this) . '-> parseRand');
- }
- } elseif (false === strpos($val, '(')) {
- $array[] = $this->parseKey($val, $options);
- } else {
- $array[] = $val;
- }
- } else {
- $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : '';
- $array[] = $this->parseKey($key, $options) . ' ' . $sort;
- }
- }
- $order = implode(',', $array);
+ if (empty($order)) {
+ return '';
}
+
+ $array = [];
+ foreach ($order as $key => $val) {
+ if ($val instanceof Expression) {
+ $array[] = $val->getValue();
+ } elseif ('[rand]' == $val) {
+ $array[] = $this->parseRand();
+ } else {
+ if (is_numeric($key)) {
+ list($key, $sort) = explode(' ', strpos($val, ' ') ? $val : $val . ' ');
+ } else {
+ $sort = $val;
+ }
+ $sort = strtoupper($sort);
+ $sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
+ $array[] = $this->parseKey($key, $options, true) . $sort;
+ }
+ }
+ $order = implode(',', $array);
+
return !empty($order) ? ' ORDER BY ' . $order : '';
}
@@ -601,6 +635,9 @@ abstract class Builder
*/
protected function parseComment($comment)
{
+ if (false !== strpos($comment, '*/')) {
+ $comment = strstr($comment, '*/', true);
+ }
return !empty($comment) ? ' /* ' . $comment . ' */' : '';
}
@@ -630,12 +667,12 @@ abstract class Builder
unset($union['type']);
foreach ($union as $u) {
if ($u instanceof \Closure) {
- $sql[] = $type . ' ' . $this->parseClosure($u, false);
+ $sql[] = $type . ' ' . $this->parseClosure($u);
} elseif (is_string($u)) {
- $sql[] = $type . ' ' . $this->parseSqlTable($u);
+ $sql[] = $type . ' ( ' . $this->parseSqlTable($u) . ' )';
}
}
- return implode(' ', $sql);
+ return ' ' . implode(' ', $sql);
}
/**
@@ -650,11 +687,7 @@ abstract class Builder
return '';
}
- if (is_array($index)) {
- $index = join(",", $index);
- }
-
- return sprintf(" FORCE INDEX ( %s ) ", $index);
+ return sprintf(" FORCE INDEX ( %s ) ", is_array($index) ? implode(',', $index) : $index);
}
/**
@@ -749,7 +782,7 @@ abstract class Builder
$fields = $options['field'];
}
- foreach ($dataSet as &$data) {
+ foreach ($dataSet as $data) {
foreach ($data as $key => $val) {
if (!in_array($key, $fields, true)) {
if ($options['strict']) {
@@ -770,19 +803,25 @@ abstract class Builder
}
$value = array_values($data);
$values[] = 'SELECT ' . implode(',', $value);
+
+ if (!isset($insertFields)) {
+ $insertFields = array_keys($data);
+ }
}
- $fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet)));
- $sql = str_replace(
+
+ foreach ($insertFields as $field) {
+ $fields[] = $this->parseKey($field, $options, true);
+ }
+
+ return str_replace(
['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
[
$replace ? 'REPLACE' : 'INSERT',
$this->parseTable($options['table'], $options),
- implode(' , ', $fields),
+ implode(' , ', $insertFields),
implode(' UNION ALL ', $values),
$this->parseComment($options['comment']),
], $this->insertAllSql);
-
- return $sql;
}
/**
diff --git a/thinkphp/library/think/db/Connection.php b/thinkphp/library/think/db/Connection.php
index 24fe07f4..7720282d 100644
--- a/thinkphp/library/think/db/Connection.php
+++ b/thinkphp/library/think/db/Connection.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
@@ -90,6 +90,8 @@ abstract class Connection
'master_num' => 1,
// 指定从服务器序号
'slave_no' => '',
+ // 模型写入后自动读取主服务器
+ 'read_master' => false,
// 是否严格检查字段是否存在
'fields_strict' => true,
// 数据返回类型
@@ -354,15 +356,15 @@ abstract class Connection
$this->bind = $bind;
}
- // 释放前次的查询结果
- if (!empty($this->PDOStatement)) {
- $this->free();
- }
-
Db::$queryTimes++;
try {
// 调试开始
$this->debug(true);
+
+ // 释放前次的查询结果
+ if (!empty($this->PDOStatement)) {
+ $this->free();
+ }
// 预处理
if (empty($this->PDOStatement)) {
$this->PDOStatement = $this->linkID->prepare($sql);
@@ -378,7 +380,7 @@ abstract class Connection
// 执行查询
$this->PDOStatement->execute();
// 调试结束
- $this->debug(false);
+ $this->debug(false, '', $master);
// 返回结果集
return $this->getResult($pdo, $procedure);
} catch (\PDOException $e) {
@@ -386,6 +388,11 @@ abstract class Connection
return $this->close()->query($sql, $bind, $master, $pdo);
}
throw new PDOException($e, $this->config, $this->getLastsql());
+ } catch (\Throwable $e) {
+ if ($this->isBreak($e)) {
+ return $this->close()->query($sql, $bind, $master, $pdo);
+ }
+ throw $e;
} catch (\Exception $e) {
if ($this->isBreak($e)) {
return $this->close()->query($sql, $bind, $master, $pdo);
@@ -397,13 +404,14 @@ abstract class Connection
/**
* 执行语句
* @access public
- * @param string $sql sql指令
- * @param array $bind 参数绑定
+ * @param string $sql sql指令
+ * @param array $bind 参数绑定
+ * @param Query $query 查询对象
* @return int
* @throws PDOException
* @throws \Exception
*/
- public function execute($sql, $bind = [])
+ public function execute($sql, $bind = [], Query $query = null)
{
$this->initConnect(true);
if (!$this->linkID) {
@@ -416,15 +424,15 @@ abstract class Connection
$this->bind = $bind;
}
- //释放前次的查询结果
- if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) {
- $this->free();
- }
-
Db::$executeTimes++;
try {
// 调试开始
$this->debug(true);
+
+ //释放前次的查询结果
+ if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) {
+ $this->free();
+ }
// 预处理
if (empty($this->PDOStatement)) {
$this->PDOStatement = $this->linkID->prepare($sql);
@@ -440,18 +448,27 @@ abstract class Connection
// 执行语句
$this->PDOStatement->execute();
// 调试结束
- $this->debug(false);
+ $this->debug(false, '', true);
+
+ if ($query && !empty($this->config['deploy']) && !empty($this->config['read_master'])) {
+ $query->readMaster();
+ }
$this->numRows = $this->PDOStatement->rowCount();
return $this->numRows;
} catch (\PDOException $e) {
if ($this->isBreak($e)) {
- return $this->close()->execute($sql, $bind);
+ return $this->close()->execute($sql, $bind, $query);
}
throw new PDOException($e, $this->config, $this->getLastsql());
+ } catch (\Throwable $e) {
+ if ($this->isBreak($e)) {
+ return $this->close()->execute($sql, $bind, $query);
+ }
+ throw $e;
} catch (\Exception $e) {
if ($this->isBreak($e)) {
- return $this->close()->execute($sql, $bind);
+ return $this->close()->execute($sql, $bind, $query);
}
throw $e;
}
@@ -466,6 +483,10 @@ abstract class Connection
*/
public function getRealSql($sql, array $bind = [])
{
+ if (is_array($sql)) {
+ $sql = implode(';', $sql);
+ }
+
foreach ($bind as $key => $val) {
$value = is_array($val) ? $val[0] : $val;
$type = is_array($val) ? $val[1] : PDO::PARAM_STR;
@@ -478,8 +499,8 @@ abstract class Connection
$sql = is_numeric($key) ?
substr_replace($sql, $value, strpos($sql, '?'), 1) :
str_replace(
- [':' . $key . ')', ':' . $key . ',', ':' . $key . ' '],
- [$value . ')', $value . ',', $value . ' '],
+ [':' . $key . ')', ':' . $key . ',', ':' . $key . ' ', ':' . $key . PHP_EOL],
+ [$value . ')', $value . ',', $value . ' ', $value . PHP_EOL],
$sql . ' ');
}
return rtrim($sql);
@@ -648,6 +669,11 @@ abstract class Connection
return $this->close()->startTrans();
}
throw $e;
+ } catch (\Error $e) {
+ if ($this->isBreak($e)) {
+ return $this->close()->startTrans();
+ }
+ throw $e;
}
}
@@ -725,7 +751,7 @@ abstract class Connection
* @param array $sqlArray SQL批处理指令
* @return boolean
*/
- public function batchQuery($sqlArray = [])
+ public function batchQuery($sqlArray = [], $bind = [], Query $query = null)
{
if (!is_array($sqlArray)) {
return false;
@@ -734,7 +760,7 @@ abstract class Connection
$this->startTrans();
try {
foreach ($sqlArray as $sql) {
- $this->execute($sql);
+ $this->execute($sql, $bind, $query);
}
// 提交事务
$this->commit();
@@ -742,6 +768,7 @@ abstract class Connection
$this->rollback();
throw $e;
}
+
return true;
}
@@ -803,6 +830,7 @@ abstract class Connection
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided',
+ 'failed with errno',
];
$error = $e->getMessage();
@@ -883,9 +911,10 @@ abstract class Connection
* @access protected
* @param boolean $start 调试开始标记 true 开始 false 结束
* @param string $sql 执行的SQL语句 留空自动获取
+ * @param boolean $master 主从标记
* @return void
*/
- protected function debug($start, $sql = '')
+ protected function debug($start, $sql = '', $master = false)
{
if (!empty($this->config['debug'])) {
// 开启数据库调试模式
@@ -902,7 +931,7 @@ abstract class Connection
$result = $this->getExplain($sql);
}
// SQL监听
- $this->trigger($sql, $runtime, $result);
+ $this->trigger($sql, $runtime, $result, $master);
}
}
}
@@ -924,19 +953,27 @@ abstract class Connection
* @param string $sql SQL语句
* @param float $runtime SQL运行时间
* @param mixed $explain SQL分析
- * @return bool
+ * @param bool $master 主从标记
+ * @return void
*/
- protected function trigger($sql, $runtime, $explain = [])
+ protected function trigger($sql, $runtime, $explain = [], $master = false)
{
if (!empty(self::$event)) {
foreach (self::$event as $callback) {
if (is_callable($callback)) {
- call_user_func_array($callback, [$sql, $runtime, $explain]);
+ call_user_func_array($callback, [$sql, $runtime, $explain, $master]);
}
}
} else {
// 未注册监听则记录到日志中
- Log::record('[ SQL ] ' . $sql . ' [ RunTime:' . $runtime . 's ]', 'sql');
+ if ($this->config['deploy']) {
+ // 分布式记录当前操作的主从
+ $master = $master ? 'master|' : 'slave|';
+ } else {
+ $master = '';
+ }
+
+ Log::record('[ SQL ] ' . $sql . ' [ ' . $master . 'RunTime:' . $runtime . 's ]', 'sql');
if (!empty($explain)) {
Log::record('[ EXPLAIN : ' . var_export($explain, true) . ' ]', 'sql');
}
diff --git a/thinkphp/library/think/db/Expression.php b/thinkphp/library/think/db/Expression.php
new file mode 100644
index 00000000..f1b92abd
--- /dev/null
+++ b/thinkphp/library/think/db/Expression.php
@@ -0,0 +1,48 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\db;
+
+class Expression
+{
+ /**
+ * 查询表达式
+ *
+ * @var string
+ */
+ protected $value;
+
+ /**
+ * 创建一个查询表达式
+ *
+ * @param string $value
+ * @return void
+ */
+ public function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * 获取表达式
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->value;
+ }
+}
diff --git a/thinkphp/library/think/db/Query.php b/thinkphp/library/think/db/Query.php
index e03ad8a7..b63c38e5 100644
--- a/thinkphp/library/think/db/Query.php
+++ b/thinkphp/library/think/db/Query.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
@@ -53,14 +53,16 @@ class Query
protected static $info = [];
// 回调事件
private static $event = [];
+ // 读取主库
+ private static $readMaster = [];
/**
* 构造函数
* @access public
* @param Connection $connection 数据库对象实例
- * @param string $model 模型名
+ * @param Model $model 模型对象
*/
- public function __construct(Connection $connection = null, $model = '')
+ public function __construct(Connection $connection = null, $model = null)
{
$this->connection = $connection ?: Db::connect([], true);
$this->prefix = $this->connection->getConfig('prefix');
@@ -131,15 +133,34 @@ class Query
}
/**
- * 获取当前的模型对象名
+ * 获取当前的模型对象实例
* @access public
- * @return string
+ * @return Model|null
*/
public function getModel()
{
return $this->model;
}
+ /**
+ * 设置后续从主库读取数据
+ * @access public
+ * @param bool $allTable
+ * @return void
+ */
+ public function readMaster($allTable = false)
+ {
+ if ($allTable) {
+ $table = '*';
+ } else {
+ $table = isset($this->options['table']) ? $this->options['table'] : $this->getTable();
+ }
+
+ static::$readMaster[$table] = true;
+
+ return $this;
+ }
+
/**
* 获取当前的builder实例对象
* @access public
@@ -238,7 +259,7 @@ class Query
*/
public function execute($sql, $bind = [])
{
- return $this->connection->execute($sql, $bind);
+ return $this->connection->execute($sql, $bind, $this);
}
/**
@@ -312,9 +333,9 @@ class Query
* @param array $sql SQL批处理指令
* @return boolean
*/
- public function batchQuery($sql = [])
+ public function batchQuery($sql = [], $bind = [])
{
- return $this->connection->batchQuery($sql);
+ return $this->connection->batchQuery($sql, $bind);
}
/**
@@ -403,7 +424,7 @@ class Query
if (empty($this->options['table'])) {
$this->options['table'] = $this->getTable();
}
- $key = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind));
+ $key = is_string($cache['key']) ? $cache['key'] : md5($this->connection->getConfig('database') . '.' . $field . serialize($this->options) . serialize($this->bind));
$result = Cache::get($key);
}
if (false === $result) {
@@ -420,7 +441,7 @@ class Query
$result += 0;
}
- if (isset($cache)) {
+ if (isset($cache) && false !== $result) {
// 缓存数据
$this->cacheData($key, $result, $cache);
}
@@ -447,7 +468,7 @@ class Query
if (empty($this->options['table'])) {
$this->options['table'] = $this->getTable();
}
- $guid = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind));
+ $guid = is_string($cache['key']) ? $cache['key'] : md5($this->connection->getConfig('database') . '.' . $field . serialize($this->options) . serialize($this->bind));
$result = Cache::get($guid);
}
if (false === $result) {
@@ -534,22 +555,24 @@ class Query
* MIN查询
* @access public
* @param string $field 字段名
+ * @param bool $force 强制转为数字类型
* @return mixed
*/
- public function min($field)
+ public function min($field, $force = true)
{
- return $this->value('MIN(' . $field . ') AS tp_min', 0, true);
+ return $this->value('MIN(' . $field . ') AS tp_min', 0, $force);
}
/**
* MAX查询
* @access public
* @param string $field 字段名
+ * @param bool $force 强制转为数字类型
* @return mixed
*/
- public function max($field)
+ public function max($field, $force = true)
{
- return $this->value('MAX(' . $field . ') AS tp_max', 0, true);
+ return $this->value('MAX(' . $field . ') AS tp_max', 0, $force);
}
/**
@@ -607,7 +630,7 @@ class Query
return true;
}
}
- return $this->setField($field, ['exp', $field . '+' . $step]);
+ return $this->setField($field, ['inc', $step]);
}
/**
@@ -635,8 +658,9 @@ class Query
$this->options = [];
return true;
}
+ return $this->setField($field, ['inc', $step]);
}
- return $this->setField($field, ['exp', $field . '-' . $step]);
+ return $this->setField($field, ['dec', $step]);
}
/**
@@ -704,7 +728,8 @@ class Query
{
// 传入的表名为数组
if (is_array($join)) {
- list($table, $alias) = each($join);
+ $table = $join;
+ $alias = array_shift($join);
} else {
$join = trim($join);
if (false !== strpos($join, '(')) {
@@ -725,13 +750,9 @@ class Query
$table = $this->getTable($table);
}
}
- }
- if (isset($alias)) {
- if (isset($this->options['alias'][$table])) {
- $table = $table . '@think' . uniqid();
+ if (isset($alias) && $table != $alias) {
+ $table = [$table => $alias];
}
- $table = [$table => $alias];
- $this->alias($table);
}
return $table;
}
@@ -769,8 +790,15 @@ class Query
{
if (empty($field)) {
return $this;
+ } elseif ($field instanceof Expression) {
+ $this->options['field'][] = $field;
+ return $this;
}
+
if (is_string($field)) {
+ if (preg_match('/[\<\'\"\(]/', $field)) {
+ return $this->fieldRaw($field);
+ }
$field = array_map('trim', explode(',', $field));
}
if (true === $field) {
@@ -794,12 +822,30 @@ class Query
}
if (isset($this->options['field'])) {
- $field = array_merge($this->options['field'], $field);
+ $field = array_merge((array) $this->options['field'], $field);
}
$this->options['field'] = array_unique($field);
return $this;
}
+ /**
+ * 表达式方式指定查询字段
+ * @access public
+ * @param string $field 字段名
+ * @param array $bind 参数绑定
+ * @return $this
+ */
+ public function fieldRaw($field, array $bind = [])
+ {
+ $this->options['field'][] = $this->raw($field);
+
+ if ($bind) {
+ $this->bind($bind);
+ }
+
+ return $this;
+ }
+
/**
* 设置数据
* @access public
@@ -828,7 +874,7 @@ class Query
{
$fields = is_string($field) ? explode(',', $field) : $field;
foreach ($fields as $field) {
- $this->data($field, ['exp', $field . '+' . $step]);
+ $this->data($field, ['inc', $step]);
}
return $this;
}
@@ -844,7 +890,7 @@ class Query
{
$fields = is_string($field) ? explode(',', $field) : $field;
foreach ($fields as $field) {
- $this->data($field, ['exp', $field . '-' . $step]);
+ $this->data($field, ['dec', $step]);
}
return $this;
}
@@ -858,25 +904,36 @@ class Query
*/
public function exp($field, $value)
{
- $this->data($field, ['exp', $value]);
+ $this->data($field, $this->raw($value));
return $this;
}
+ /**
+ * 使用表达式设置数据
+ * @access public
+ * @param mixed $value 表达式
+ * @return Expression
+ */
+ public function raw($value)
+ {
+ return new Expression($value);
+ }
+
/**
* 指定JOIN查询字段
* @access public
* @param string|array $table 数据表
* @param string|array $field 查询字段
- * @param string|array $on JOIN条件
+ * @param mixed $on JOIN条件
* @param string $type JOIN类型
* @return $this
*/
public function view($join, $field = true, $on = null, $type = 'INNER')
{
$this->options['view'] = true;
- if (is_array($join) && key($join) !== 0) {
+ if (is_array($join) && key($join) === 0) {
foreach ($join as $key => $val) {
- $this->view($key, $val[0], isset($val[1]) ? $val[1] : null, isset($val[2]) ? $val[2] : 'INNER');
+ $this->view($val[0], $val[1], isset($val[2]) ? $val[2] : null, isset($val[3]) ? $val[3] : 'INNER');
}
} else {
$fields = [];
@@ -975,6 +1032,37 @@ class Query
return $this;
}
+ /**
+ * 指定表达式查询条件
+ * @access public
+ * @param string $where 查询条件
+ * @param array $bind 参数绑定
+ * @param string $logic 查询逻辑 and or xor
+ * @return $this
+ */
+ public function whereRaw($where, $bind = [], $logic = 'AND')
+ {
+ $this->options['where'][$logic][] = $this->raw($where);
+
+ if ($bind) {
+ $this->bind($bind);
+ }
+
+ return $this;
+ }
+
+ /**
+ * 指定表达式查询条件 OR
+ * @access public
+ * @param string $where 查询条件
+ * @param array $bind 参数绑定
+ * @return $this
+ */
+ public function whereOrRaw($where, $bind = [])
+ {
+ return $this->whereRaw($where, $bind, 'OR');
+ }
+
/**
* 指定Null查询条件
* @access public
@@ -984,7 +1072,7 @@ class Query
*/
public function whereNull($field, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'null', null);
+ $this->parseWhereExp($logic, $field, 'null', null, [], true);
return $this;
}
@@ -997,7 +1085,7 @@ class Query
*/
public function whereNotNull($field, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'notnull', null);
+ $this->parseWhereExp($logic, $field, 'notnull', null, [], true);
return $this;
}
@@ -1037,7 +1125,7 @@ class Query
*/
public function whereIn($field, $condition, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'in', $condition);
+ $this->parseWhereExp($logic, $field, 'in', $condition, [], true);
return $this;
}
@@ -1051,7 +1139,7 @@ class Query
*/
public function whereNotIn($field, $condition, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'not in', $condition);
+ $this->parseWhereExp($logic, $field, 'not in', $condition, [], true);
return $this;
}
@@ -1065,7 +1153,7 @@ class Query
*/
public function whereLike($field, $condition, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'like', $condition);
+ $this->parseWhereExp($logic, $field, 'like', $condition, [], true);
return $this;
}
@@ -1079,7 +1167,7 @@ class Query
*/
public function whereNotLike($field, $condition, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'not like', $condition);
+ $this->parseWhereExp($logic, $field, 'not like', $condition, [], true);
return $this;
}
@@ -1093,7 +1181,7 @@ class Query
*/
public function whereBetween($field, $condition, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'between', $condition);
+ $this->parseWhereExp($logic, $field, 'between', $condition, [], true);
return $this;
}
@@ -1107,7 +1195,7 @@ class Query
*/
public function whereNotBetween($field, $condition, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'not between', $condition);
+ $this->parseWhereExp($logic, $field, 'not between', $condition, [], true);
return $this;
}
@@ -1121,7 +1209,7 @@ class Query
*/
public function whereExp($field, $condition, $logic = 'AND')
{
- $this->parseWhereExp($logic, $field, 'exp', $condition);
+ $this->parseWhereExp($logic, $field, 'exp', $this->raw($condition), [], true);
return $this;
}
@@ -1148,9 +1236,10 @@ class Query
* @param mixed $op 查询表达式
* @param mixed $condition 查询条件
* @param array $param 查询参数
+ * @param bool $strict 严格模式
* @return void
*/
- protected function parseWhereExp($logic, $field, $op, $condition, $param = [])
+ protected function parseWhereExp($logic, $field, $op, $condition, $param = [], $strict = false)
{
$logic = strtoupper($logic);
if ($field instanceof \Closure) {
@@ -1161,8 +1250,17 @@ class Query
if (is_string($field) && !empty($this->options['via']) && !strpos($field, '.')) {
$field = $this->options['via'] . '.' . $field;
}
- if (is_string($field) && preg_match('/[,=\>\<\'\"\(\s]/', $field)) {
- $where[] = ['exp', $field];
+
+ if ($field instanceof Expression) {
+ return $this->whereRaw($field, is_array($op) ? $op : []);
+ } elseif ($strict) {
+ // 使用严格模式查询
+ $where[$field] = [$op, $condition];
+
+ // 记录一个字段多次查询条件
+ $this->options['multi'][$logic][$field][] = $where[$field];
+ } elseif (is_string($field) && preg_match('/[,=\>\<\'\"\(\s]/', $field)) {
+ $where[] = ['exp', $this->raw($field)];
if (is_array($op)) {
// 参数绑定
$this->bind($op);
@@ -1183,21 +1281,28 @@ class Query
$where[$field] = $param;
} elseif (in_array(strtolower($op), ['null', 'notnull', 'not null'])) {
// null查询
- $where[$field] = [$op, ''];
+ $where[$field] = [$op, ''];
+
$this->options['multi'][$logic][$field][] = $where[$field];
} elseif (is_null($condition)) {
// 字段相等查询
- $where[$field] = ['eq', $op];
+ $where[$field] = ['eq', $op];
+
$this->options['multi'][$logic][$field][] = $where[$field];
} else {
- $where[$field] = [$op, $condition, isset($param[2]) ? $param[2] : null];
- if ('exp' == strtolower($op) && isset($param[2]) && is_array($param[2])) {
+ if ('exp' == strtolower($op)) {
+ $where[$field] = ['exp', $this->raw($condition)];
// 参数绑定
- $this->bind($param[2]);
+ if (isset($param[2]) && is_array($param[2])) {
+ $this->bind($param[2]);
+ }
+ } else {
+ $where[$field] = [$op, $condition];
}
// 记录一个字段多次查询条件
$this->options['multi'][$logic][$field][] = $where[$field];
}
+
if (!empty($where)) {
if (!isset($this->options['where'][$logic])) {
$this->options['where'][$logic] = [];
@@ -1239,6 +1344,7 @@ class Query
$logic = strtoupper($logic);
if (isset($this->options['where'][$logic][$field])) {
unset($this->options['where'][$logic][$field]);
+ unset($this->options['multi'][$logic][$field]);
}
return $this;
}
@@ -1414,31 +1520,59 @@ class Query
*/
public function order($field, $order = null)
{
- if (!empty($field)) {
- if (is_string($field)) {
- if (!empty($this->options['via'])) {
- $field = $this->options['via'] . '.' . $field;
- }
- $field = empty($order) ? $field : [$field => $order];
- } elseif (!empty($this->options['via'])) {
- foreach ($field as $key => $val) {
- if (is_numeric($key)) {
- $field[$key] = $this->options['via'] . '.' . $val;
- } else {
- $field[$this->options['via'] . '.' . $key] = $val;
- unset($field[$key]);
- }
- }
+ if (empty($field)) {
+ return $this;
+ } elseif ($field instanceof Expression) {
+ $this->options['order'][] = $field;
+ return $this;
+ }
+
+ if (is_string($field)) {
+ if (!empty($this->options['via'])) {
+ $field = $this->options['via'] . '.' . $field;
}
- if (!isset($this->options['order'])) {
- $this->options['order'] = [];
- }
- if (is_array($field)) {
- $this->options['order'] = array_merge($this->options['order'], $field);
+ if (strpos($field, ',')) {
+ $field = array_map('trim', explode(',', $field));
} else {
- $this->options['order'][] = $field;
+ $field = empty($order) ? $field : [$field => $order];
+ }
+ } elseif (!empty($this->options['via'])) {
+ foreach ($field as $key => $val) {
+ if (is_numeric($key)) {
+ $field[$key] = $this->options['via'] . '.' . $val;
+ } else {
+ $field[$this->options['via'] . '.' . $key] = $val;
+ unset($field[$key]);
+ }
}
}
+ if (!isset($this->options['order'])) {
+ $this->options['order'] = [];
+ }
+ if (is_array($field)) {
+ $this->options['order'] = array_merge($this->options['order'], $field);
+ } else {
+ $this->options['order'][] = $field;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 表达式方式指定Field排序
+ * @access public
+ * @param string $field 排序字段
+ * @param array $bind 参数绑定
+ * @return $this
+ */
+ public function orderRaw($field, array $bind = [])
+ {
+ $this->options['order'][] = $this->raw($field);
+
+ if ($bind) {
+ $this->bind($bind);
+ }
+
return $this;
}
@@ -1523,7 +1657,12 @@ class Query
{
if (is_array($alias)) {
foreach ($alias as $key => $val) {
- $this->options['alias'][$key] = $val;
+ if (false !== strpos($key, '__')) {
+ $table = $this->parseSqlTable($key);
+ } else {
+ $table = $key;
+ }
+ $this->options['alias'][$table] = $val;
}
} else {
if (isset($this->options['table'])) {
@@ -1651,46 +1790,49 @@ class Query
* 查询日期或者时间
* @access public
* @param string $field 日期字段名
- * @param string $op 比较运算符或者表达式
+ * @param string|array $op 比较运算符或者表达式
* @param string|array $range 比较范围
* @return $this
*/
public function whereTime($field, $op, $range = null)
{
if (is_null($range)) {
- // 使用日期表达式
- $date = getdate();
- switch (strtolower($op)) {
- case 'today':
- case 'd':
- $range = ['today', 'tomorrow'];
- break;
- case 'week':
- case 'w':
- $range = 'this week 00:00:00';
- break;
- case 'month':
- case 'm':
- $range = mktime(0, 0, 0, $date['mon'], 1, $date['year']);
- break;
- case 'year':
- case 'y':
- $range = mktime(0, 0, 0, 1, 1, $date['year']);
- break;
- case 'yesterday':
- $range = ['yesterday', 'today'];
- break;
- case 'last week':
- $range = ['last week 00:00:00', 'this week 00:00:00'];
- break;
- case 'last month':
- $range = [date('y-m-01', strtotime('-1 month')), mktime(0, 0, 0, $date['mon'], 1, $date['year'])];
- break;
- case 'last year':
- $range = [mktime(0, 0, 0, 1, 1, $date['year'] - 1), mktime(0, 0, 0, 1, 1, $date['year'])];
- break;
- default:
- $range = $op;
+ if (is_array($op)) {
+ $range = $op;
+ } else {
+ // 使用日期表达式
+ switch (strtolower($op)) {
+ case 'today':
+ case 'd':
+ $range = ['today', 'tomorrow'];
+ break;
+ case 'week':
+ case 'w':
+ $range = ['this week 00:00:00', 'next week 00:00:00'];
+ break;
+ case 'month':
+ case 'm':
+ $range = ['first Day of this month 00:00:00', 'first Day of next month 00:00:00'];
+ break;
+ case 'year':
+ case 'y':
+ $range = ['this year 1/1', 'next year 1/1'];
+ break;
+ case 'yesterday':
+ $range = ['yesterday', 'today'];
+ break;
+ case 'last week':
+ $range = ['last week 00:00:00', 'this week 00:00:00'];
+ break;
+ case 'last month':
+ $range = ['first Day of last month 00:00:00', 'first Day of this month 00:00:00'];
+ break;
+ case 'last year':
+ $range = ['last year 1/1', 'this year 1/1'];
+ break;
+ default:
+ $range = $op;
+ }
}
$op = is_array($range) ? 'between' : '>';
}
@@ -1735,7 +1877,7 @@ class Query
$schema = $guid;
}
// 读取缓存
- if (is_file(RUNTIME_PATH . 'schema/' . $schema . '.php')) {
+ if (!App::$debug && is_file(RUNTIME_PATH . 'schema/' . $schema . '.php')) {
$info = include RUNTIME_PATH . 'schema/' . $schema . '.php';
} else {
$info = $this->connection->getFields($guid);
@@ -1810,7 +1952,9 @@ class Query
*/
protected function getFieldBindType($type)
{
- if (preg_match('/(int|double|float|decimal|real|numeric|serial|bit)/is', $type)) {
+ if (0 === strpos($type, 'set') || 0 === strpos($type, 'enum')) {
+ $bind = PDO::PARAM_STR;
+ } elseif (preg_match('/(int|double|float|decimal|real|numeric|serial|bit)/is', $type)) {
$bind = PDO::PARAM_INT;
} elseif (preg_match('/bool/is', $type)) {
$bind = PDO::PARAM_BOOL;
@@ -1892,11 +2036,10 @@ class Query
$with = explode(',', $with);
}
- $first = true;
- $currentModel = $this->model;
+ $first = true;
/** @var Model $class */
- $class = new $currentModel;
+ $class = $this->model;
foreach ($with as $key => $relation) {
$subRelation = '';
$closure = false;
@@ -1955,7 +2098,7 @@ class Query
$relation = $key;
}
$relation = Loader::parseName($relation, 1, false);
- $count = '(' . (new $this->model)->$relation()->getRelationCountQuery($closure) . ')';
+ $count = '(' . $this->model->$relation()->getRelationCountQuery($closure) . ')';
$this->field([$count => Loader::parseName($relation) . '_count']);
}
}
@@ -2082,7 +2225,7 @@ class Query
}
// 执行操作
- $result = 0 === $sql ? 0 : $this->execute($sql, $bind);
+ $result = 0 === $sql ? 0 : $this->execute($sql, $bind, $this);
if ($result) {
$sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null);
$lastInsId = $this->getLastInsID($sequence);
@@ -2118,27 +2261,40 @@ class Query
/**
* 批量插入记录
* @access public
- * @param mixed $dataSet 数据集
- * @param boolean $replace 是否replace
+ * @param mixed $dataSet 数据集
+ * @param boolean $replace 是否replace
+ * @param integer $limit 每次写入数据限制
* @return integer|string
*/
- public function insertAll(array $dataSet, $replace = false)
+ public function insertAll(array $dataSet, $replace = false, $limit = null)
{
// 分析查询表达式
$options = $this->parseExpress();
if (!is_array(reset($dataSet))) {
return false;
}
+
// 生成SQL语句
- $sql = $this->builder->insertAll($dataSet, $options, $replace);
+ if (is_null($limit)) {
+ $sql = $this->builder->insertAll($dataSet, $options, $replace);
+ } else {
+ $array = array_chunk($dataSet, $limit, true);
+ foreach ($array as $item) {
+ $sql[] = $this->builder->insertAll($item, $options, $replace);
+ }
+ }
+
// 获取参数绑定
$bind = $this->getBind();
if ($options['fetch_sql']) {
// 获取实际执行的SQL语句
return $this->connection->getRealSql($sql, $bind);
+ } elseif (is_array($sql)) {
+ // 执行操作
+ return $this->batchQuery($sql, $bind, $this);
} else {
// 执行操作
- return $this->execute($sql, $bind);
+ return $this->execute($sql, $bind, $this);
}
}
@@ -2164,7 +2320,7 @@ class Query
return $this->connection->getRealSql($sql, $bind);
} else {
// 执行操作
- return $this->execute($sql, $bind);
+ return $this->execute($sql, $bind, $this);
}
}
@@ -2231,7 +2387,7 @@ class Query
Cache::clear($options['cache']['tag']);
}
// 执行操作
- $result = '' == $sql ? 0 : $this->execute($sql, $bind);
+ $result = '' == $sql ? 0 : $this->execute($sql, $bind, $this);
if ($result) {
if (is_string($pk) && isset($where[$pk])) {
$data[$pk] = $where[$pk];
@@ -2300,7 +2456,7 @@ class Query
// 判断查询缓存
$cache = $options['cache'];
unset($options['cache']);
- $key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options) . serialize($this->bind));
+ $key = is_string($cache['key']) ? $cache['key'] : md5($this->connection->getConfig('database') . '.' . serialize($options) . serialize($this->bind));
$resultSet = Cache::get($key);
}
if (false === $resultSet) {
@@ -2334,11 +2490,10 @@ class Query
// 数据列表读取后的处理
if (!empty($this->model)) {
// 生成模型对象
- $modelName = $this->model;
if (count($resultSet) > 0) {
foreach ($resultSet as $key => $result) {
/** @var Model $model */
- $model = new $modelName($result);
+ $model = $this->model->newInstance($result);
$model->isUpdate(true);
// 关联查询
@@ -2358,7 +2513,7 @@ class Query
// 模型数据集转换
$resultSet = $model->toCollection($resultSet);
} else {
- $resultSet = (new $modelName)->toCollection($resultSet);
+ $resultSet = $this->model->toCollection($resultSet);
}
} elseif ('collection' == $this->connection->getConfig('resultset_type')) {
// 返回Collection对象
@@ -2402,10 +2557,16 @@ class Query
} elseif (is_array($value) && is_string($value[0]) && 'eq' == strtolower($value[0])) {
$data = $value[1];
}
+ $prefix = $this->connection->getConfig('database') . '.';
+
if (isset($data)) {
- return 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
- } else {
- return md5(serialize($options) . serialize($bind));
+ return 'think:' . $prefix . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
+ }
+
+ try {
+ return md5($prefix . serialize($options) . serialize($bind));
+ } catch (\Exception $e) {
+ throw new Exception('closure not support cache(true)');
}
}
@@ -2442,11 +2603,11 @@ class Query
// 判断查询缓存
$cache = $options['cache'];
if (true === $cache['key'] && !is_null($data) && !is_array($data)) {
- $key = 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
+ $key = 'think:' . $this->connection->getConfig('database') . '.' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
} elseif (is_string($cache['key'])) {
$key = $cache['key'];
} elseif (!isset($key)) {
- $key = md5(serialize($options) . serialize($this->bind));
+ $key = md5($this->connection->getConfig('database') . '.' . serialize($options) . serialize($this->bind));
}
$result = Cache::get($key);
}
@@ -2484,7 +2645,7 @@ class Query
$result = isset($resultSet[0]) ? $resultSet[0] : null;
}
- if (isset($cache) && false !== $result) {
+ if (isset($cache) && $result) {
// 缓存数据
$this->cacheData($key, $result, $cache);
}
@@ -2494,8 +2655,7 @@ class Query
if (!empty($result)) {
if (!empty($this->model)) {
// 返回模型对象
- $model = $this->model;
- $result = new $model($result);
+ $result = $this->model->newInstance($result);
$result->isUpdate(true, isset($options['where']['AND']) ? $options['where']['AND'] : null);
// 关联查询
if (!empty($options['relation'])) {
@@ -2526,7 +2686,8 @@ class Query
protected function throwNotFound($options = [])
{
if (!empty($this->model)) {
- throw new ModelNotFoundException('model data Not Found:' . $this->model, $this->model, $options);
+ $class = get_class($this->model);
+ throw new ModelNotFoundException('model data Not Found:' . $class, $class, $options);
} else {
$table = is_array($options['table']) ? key($options['table']) : $options['table'];
throw new DataNotFoundException('table data not Found:' . $table, $table, $options);
@@ -2574,48 +2735,54 @@ class Query
public function chunk($count, $callback, $column = null, $order = 'asc')
{
$options = $this->getOptions();
- if (isset($options['table'])) {
- $table = is_array($options['table']) ? key($options['table']) : $options['table'];
- } else {
- $table = '';
- }
- $column = $column ?: $this->getPk($table);
- if (is_array($column)) {
- $column = $column[0];
+ if (empty($options['table'])) {
+ $options['table'] = $this->getTable();
}
+ $column = $column ?: $this->getPk($options);
+
if (isset($options['order'])) {
if (App::$debug) {
throw new \LogicException('chunk not support call order');
}
unset($options['order']);
}
- $bind = $this->bind;
- $resultSet = $this->options($options)->limit($count)->order($column, $order)->select();
- if (strpos($column, '.')) {
- list($alias, $key) = explode('.', $column);
+ $bind = $this->bind;
+ if (is_array($column)) {
+ $times = 1;
+ $query = $this->options($options)->page($times, $count);
} else {
- $key = $column;
- }
- if ($resultSet instanceof Collection) {
- $resultSet = $resultSet->all();
- }
-
- while (!empty($resultSet)) {
- if (false === call_user_func($callback, $resultSet)) {
- return false;
+ if (strpos($column, '.')) {
+ list($alias, $key) = explode('.', $column);
+ } else {
+ $key = $column;
}
- $end = end($resultSet);
- $lastId = is_array($end) ? $end[$key] : $end->$key;
- $resultSet = $this->options($options)
- ->limit($count)
- ->bind($bind)
- ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId)
- ->order($column, $order)
- ->select();
+ $query = $this->options($options)->limit($count);
+ }
+ $resultSet = $query->order($column, $order)->select();
+
+ while (count($resultSet) > 0) {
if ($resultSet instanceof Collection) {
$resultSet = $resultSet->all();
}
+
+ if (false === call_user_func($callback, $resultSet)) {
+ return false;
+ }
+
+ if (is_array($column)) {
+ $times++;
+ $query = $this->options($options)->page($times, $count);
+ } else {
+ $end = end($resultSet);
+ $lastId = is_array($end) ? $end[$key] : $end->getData($key);
+ $query = $this->options($options)
+ ->limit($count)
+ ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId);
+ }
+
+ $resultSet = $query->bind($bind)->order($column, $order)->select();
}
+
return true;
}
@@ -2692,7 +2859,7 @@ class Query
Cache::clear($options['cache']['tag']);
}
// 执行操作
- $result = $this->execute($sql, $bind);
+ $result = $this->execute($sql, $bind, $this);
if ($result) {
if (!is_array($data) && is_string($pk) && isset($key) && strpos($key, '|')) {
list($a, $val) = explode('|', $key);
@@ -2777,6 +2944,10 @@ class Query
}
}
+ if (isset(static::$readMaster['*']) || (is_string($options['table']) && isset(static::$readMaster[$options['table']]))) {
+ $options['master'] = true;
+ }
+
foreach (['join', 'union', 'group', 'having', 'limit', 'order', 'force', 'comment'] as $name) {
if (!isset($options[$name])) {
$options[$name] = '';
diff --git a/thinkphp/library/think/db/builder/Mysql.php b/thinkphp/library/think/db/builder/Mysql.php
index 5bc9d03b..8eee746f 100644
--- a/thinkphp/library/think/db/builder/Mysql.php
+++ b/thinkphp/library/think/db/builder/Mysql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
@@ -12,28 +12,93 @@
namespace think\db\builder;
use think\db\Builder;
+use think\Exception;
/**
* mysql数据库驱动
*/
class Mysql extends Builder
{
- protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
+
+ protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES %DATA% %COMMENT%';
+ protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
+
+ /**
+ * 生成insertall SQL
+ * @access public
+ * @param array $dataSet 数据集
+ * @param array $options 表达式
+ * @param bool $replace 是否replace
+ * @return string
+ * @throws Exception
+ */
+ public function insertAll($dataSet, $options = [], $replace = false)
+ {
+ // 获取合法的字段
+ if ('*' == $options['field']) {
+ $fields = array_keys($this->query->getFieldsType($options['table']));
+ } else {
+ $fields = $options['field'];
+ }
+
+ foreach ($dataSet as $data) {
+ foreach ($data as $key => $val) {
+ if (!in_array($key, $fields, true)) {
+ if ($options['strict']) {
+ throw new Exception('fields not exists:[' . $key . ']');
+ }
+ unset($data[$key]);
+ } elseif (is_null($val)) {
+ $data[$key] = 'NULL';
+ } elseif (is_scalar($val)) {
+ $data[$key] = $this->parseValue($val, $key);
+ } elseif (is_object($val) && method_exists($val, '__toString')) {
+ // 对象数据写入
+ $data[$key] = $val->__toString();
+ } else {
+ // 过滤掉非标量数据
+ unset($data[$key]);
+ }
+ }
+ $value = array_values($data);
+ $values[] = '( ' . implode(',', $value) . ' )';
+
+ if (!isset($insertFields)) {
+ $insertFields = array_map([$this, 'parseKey'], array_keys($data));
+ }
+ }
+
+ return str_replace(
+ ['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
+ [
+ $replace ? 'REPLACE' : 'INSERT',
+ $this->parseTable($options['table'], $options),
+ implode(' , ', $insertFields),
+ implode(' , ', $values),
+ $this->parseComment($options['comment']),
+ ], $this->insertAllSql);
+ }
/**
* 字段和表名处理
* @access protected
- * @param string $key
+ * @param mixed $key
* @param array $options
* @return string
*/
- protected function parseKey($key, $options = [])
+ protected function parseKey($key, $options = [], $strict = false)
{
+ if (is_numeric($key)) {
+ return $key;
+ } elseif ($key instanceof Expression) {
+ return $key->getValue();
+ }
+
$key = trim($key);
if (strpos($key, '$.') && false === strpos($key, '(')) {
// JSON字段支持
list($field, $name) = explode('$.', $key);
- $key = 'json_extract(' . $field . ', \'$.' . $name . '\')';
+ return 'json_extract(' . $field . ', \'$.' . $name . '\')';
} elseif (strpos($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
list($table, $key) = explode('.', $key, 2);
if ('__TABLE__' == $table) {
@@ -43,7 +108,8 @@ class Mysql extends Builder
$table = $options['alias'][$table];
}
}
- if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) {
+
+ if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)`.\s]/', $key))) {
$key = '`' . $key . '`';
}
if (isset($table)) {
diff --git a/thinkphp/library/think/db/builder/Pgsql.php b/thinkphp/library/think/db/builder/Pgsql.php
index b690401c..acc22896 100644
--- a/thinkphp/library/think/db/builder/Pgsql.php
+++ b/thinkphp/library/think/db/builder/Pgsql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
@@ -44,12 +44,18 @@ class Pgsql extends Builder
/**
* 字段和表名处理
* @access protected
- * @param string $key
+ * @param mixed $key
* @param array $options
* @return string
*/
- protected function parseKey($key, $options = [])
+ protected function parseKey($key, $options = [], $strict = false)
{
+ if (is_numeric($key)) {
+ return $key;
+ } elseif ($key instanceof Expression) {
+ return $key->getValue();
+ }
+
$key = trim($key);
if (strpos($key, '$.') && false === strpos($key, '(')) {
// JSON字段支持
diff --git a/thinkphp/library/think/db/builder/Sqlite.php b/thinkphp/library/think/db/builder/Sqlite.php
index 28a5d6f1..c727f04b 100644
--- a/thinkphp/library/think/db/builder/Sqlite.php
+++ b/thinkphp/library/think/db/builder/Sqlite.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
@@ -52,12 +52,18 @@ class Sqlite extends Builder
/**
* 字段和表名处理
* @access protected
- * @param string $key
+ * @param mixed $key
* @param array $options
* @return string
*/
- protected function parseKey($key, $options = [])
+ protected function parseKey($key, $options = [], $strict = false)
{
+ if (is_numeric($key)) {
+ return $key;
+ } elseif ($key instanceof Expression) {
+ return $key->getValue();
+ }
+
$key = trim($key);
if (strpos($key, '.')) {
list($table, $key) = explode('.', $key, 2);
diff --git a/thinkphp/library/think/db/builder/Sqlsrv.php b/thinkphp/library/think/db/builder/Sqlsrv.php
index 59ea021f..f79ae030 100644
--- a/thinkphp/library/think/db/builder/Sqlsrv.php
+++ b/thinkphp/library/think/db/builder/Sqlsrv.php
@@ -12,6 +12,7 @@
namespace think\db\builder;
use think\db\Builder;
+use think\db\Expression;
/**
* Sqlsrv数据库驱动
@@ -34,25 +35,29 @@ class Sqlsrv extends Builder
*/
protected function parseOrder($order, $options = [])
{
- if (is_array($order)) {
- $array = [];
- foreach ($order as $key => $val) {
- if (is_numeric($key)) {
- if (false === strpos($val, '(')) {
- $array[] = $this->parseKey($val, $options);
- } elseif ('[rand]' == $val) {
- $array[] = $this->parseRand();
- } else {
- $array[] = $val;
- }
- } else {
- $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : '';
- $array[] = $this->parseKey($key, $options) . ' ' . $sort;
- }
- }
- $order = implode(',', $array);
+ if (empty($order)) {
+ return ' ORDER BY rand()';
}
- return !empty($order) ? ' ORDER BY ' . $order : ' ORDER BY rand()';
+
+ $array = [];
+ foreach ($order as $key => $val) {
+ if ($val instanceof Expression) {
+ $array[] = $val->getValue();
+ } elseif (is_numeric($key)) {
+ if (false === strpos($val, '(')) {
+ $array[] = $this->parseKey($val, $options);
+ } elseif ('[rand]' == $val) {
+ $array[] = $this->parseRand();
+ } else {
+ $array[] = $val;
+ }
+ } else {
+ $sort = in_array(strtolower(trim($val)), ['asc', 'desc'], true) ? ' ' . $val : '';
+ $array[] = $this->parseKey($key, $options, true) . ' ' . $sort;
+ }
+ }
+
+ return ' ORDER BY ' . implode(',', $array);
}
/**
@@ -68,12 +73,17 @@ class Sqlsrv extends Builder
/**
* 字段和表名处理
* @access protected
- * @param string $key
+ * @param mixed $key
* @param array $options
* @return string
*/
- protected function parseKey($key, $options = [])
+ protected function parseKey($key, $options = [], $strict = false)
{
+ if (is_numeric($key)) {
+ return $key;
+ } elseif ($key instanceof Expression) {
+ return $key->getValue();
+ }
$key = trim($key);
if (strpos($key, '.') && !preg_match('/[,\'\"\(\)\[\s]/', $key)) {
list($table, $key) = explode('.', $key, 2);
@@ -84,7 +94,7 @@ class Sqlsrv extends Builder
$table = $options['alias'][$table];
}
}
- if (!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/', $key)) {
+ if ('*' != $key && ($strict || !preg_match('/[,\'\"\*\(\)\[.\s]/', $key))) {
$key = '[' . $key . ']';
}
if (isset($table)) {
diff --git a/thinkphp/library/think/db/connector/Mysql.php b/thinkphp/library/think/db/connector/Mysql.php
index 9d146c71..be1a85ce 100644
--- a/thinkphp/library/think/db/connector/Mysql.php
+++ b/thinkphp/library/think/db/connector/Mysql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
diff --git a/thinkphp/library/think/db/connector/Pgsql.php b/thinkphp/library/think/db/connector/Pgsql.php
index 761fbac4..bbcf5768 100644
--- a/thinkphp/library/think/db/connector/Pgsql.php
+++ b/thinkphp/library/think/db/connector/Pgsql.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
diff --git a/thinkphp/library/think/db/connector/Sqlite.php b/thinkphp/library/think/db/connector/Sqlite.php
index fd7f02b0..c4e3a724 100644
--- a/thinkphp/library/think/db/connector/Sqlite.php
+++ b/thinkphp/library/think/db/connector/Sqlite.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
diff --git a/thinkphp/library/think/db/exception/BindParamException.php b/thinkphp/library/think/db/exception/BindParamException.php
index d0e2387b..4ed19546 100644
--- a/thinkphp/library/think/db/exception/BindParamException.php
+++ b/thinkphp/library/think/db/exception/BindParamException.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
diff --git a/thinkphp/library/think/db/exception/DataNotFoundException.php b/thinkphp/library/think/db/exception/DataNotFoundException.php
index e399b063..f2542ac6 100644
--- a/thinkphp/library/think/db/exception/DataNotFoundException.php
+++ b/thinkphp/library/think/db/exception/DataNotFoundException.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
diff --git a/thinkphp/library/think/db/exception/ModelNotFoundException.php b/thinkphp/library/think/db/exception/ModelNotFoundException.php
index 2180ab07..6e5f930c 100644
--- a/thinkphp/library/think/db/exception/ModelNotFoundException.php
+++ b/thinkphp/library/think/db/exception/ModelNotFoundException.php
@@ -2,7 +2,7 @@
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
-// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
+// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
diff --git a/view/crmebN/pages/orders-con/orders-con.js b/view/crmebN/pages/orders-con/orders-con.js
index 6f5b7919..b9bb340e 100644
--- a/view/crmebN/pages/orders-con/orders-con.js
+++ b/view/crmebN/pages/orders-con/orders-con.js
@@ -66,7 +66,7 @@ Page({
})
setTimeout(function () {
wx.navigateTo({ //跳转至指定页面并关闭其他打开的所有页面(这个最好用在返回至首页的的时候)
- url: '/pages/orders-con/orders-con?order_id=' + data.result.orderId
+ url: '/pages/orders-con/orders-con?order_id=' + data.result.order_id
})
}, 1200)
},
diff --git a/view/crmebN/pages/product-con/index.wxml b/view/crmebN/pages/product-con/index.wxml
index f61f8452..fd8e9ff3 100644
--- a/view/crmebN/pages/product-con/index.wxml
+++ b/view/crmebN/pages/product-con/index.wxml
@@ -78,7 +78,7 @@
{{reply.comment}}
{{reply.add_time}}
-
+
管理员回复:
{{reply.merchant_reply_content}}
{{reply.merchant_reply_time}}
|