<?php
/**
 * 事务块
 * @author: JiaoYuKun
 * @day: 2019/12/9
 */
namespace traits;
use think\Db;
use think\Loader;
use think\Lang;
trait ModelTrait
{

    protected $withTable = [];

    public static $url_enpity = null;
    public static $url_lock = false;
    public static $url_lock_key = "";
    public static $url_lock_suffix = "";

    public static $url_lock_timeout = 120;

    public static $url_error_msg = "您的请求过于频繁，请您稍后再试！";

    /**
     * 开启事务
     */
    public static function beginTrans()
    {
        if (static::$url_lock) {
//            var_dump(static::$url_lock);
            if(!static::$url_lock_suffix){
                //用继承的类名当锁的key
                static::$url_lock_suffix = get_called_class()."-lock-suffix";
            }

            static::$url_enpity = new \bw\UrlLock(static::$url_lock_key, static::$url_lock_suffix, static::$url_lock_timeout, static::$url_error_msg);
            static::$url_enpity->lock();
        }
        Db::startTrans();
    }

    /**
     * 提交事务
     */
    public static function commitTrans()
    {
        if(static::$url_enpity)static::$url_enpity->free();
        Db::commit();
    }

    /**
     * 关闭事务
     */
    public static function rollbackTrans()
    {
        if(static::$url_enpity){
//           var_dump(22222222);
            static::$url_enpity->free();
        };
        Db::rollback();
    }

    /**
     * 根据结果提交滚回事务
     * @param $res
     */
    public static function checkTrans($res)
    {
        if ($res) {
            static::commitTrans();
        } else {
            static::rollbackTrans();
        }
    }



    public static function check($param,$rule=[],$rule_msg=[])
    {
        $self= new static;
        if(property_exists($self,'rule')){
            $rule = array_merge(static::$rule,$rule);
        }
        if(property_exists($self,'rule_msg')){
            $rule_msg = array_merge(static::$rule_msg,$rule_msg);
        }
        $validate = new \think\Validate($rule, $rule_msg);
        $result = $validate->check($param);
        if (!$result) {
            if (method_exists($self, 'setError')) {
                return self::setError($validate->getError());
            } else {
                throw new \Exception($validate->getError());
            }
        }
        return true;
    }

    /**
     * 设置异常
     * @param string $errorMsg
     * @return bool
     */
    protected static function setException($errorMsg = "操作失败,请稍候再试!")
    {
        throw new \Exception($errorMsg);
    }



    /**
     * 带有乐观锁的修改
     * Power: Mikkle
     * Email：776329498@qq.com
     * @param $save_data　　　修改的数据
     * @param string $edit_pk  修改的ＩＤ字段名称
     * @param string $version_field　　乐观锁版本号字段名称
     * @return array
     */
    public function editDateWithLock($save_data,$edit_pk="",$version_field=""){
        if (empty($version_field)){
            $version_field = isset($this->versionField) ? $this->versionField : "edit_version";
        }
        if (empty($edit_pk)){
            $edit_pk = isset($this->editPk) ? $this->editPk : $this->getPk();
        }
        //判断PK字段是否存在
        if (!isset($save_data[$edit_pk])||!isset($save_data[$version_field])){
            throw new \Exception("参数缺失");
        }else{
            //设置升级检索条件 PK和版本号
            $map[$edit_pk] = $save_data[$edit_pk];
            $map[$version_field] = $save_data[$version_field];
            //剔除PK
            unset($save_data[$edit_pk]);
        }
            //检测版本字段
            if($this->hasColumn($version_field)){
                throw new \Exception("乐观锁版本字段[$version_field]不存在");
            }
            $original_data = $this->where($map)->find();
            if (empty($original_data)){
                throw new \Exception("此条信息已经变动了,请重新操作!");
            }
            foreach ($save_data as $item=>$value){
                if (isset($original_data[$item])){
                    //修改的数值不变时候 剔除
                    if ($original_data[$item]==$value){
                        unset( $save_data[$item]);
                    }elseif($item!=$version_field){
                        unset( $original_data[$item]);
                    }
                }else{
                    //修改的字段不存在 剔除
                    unset( $save_data[$item]);
                }
            }
            if(empty($save_data)){
                throw new \Exception("修改的数值无变化");
            }
            //版本号升级
            $save_data[$version_field]=(int)$original_data[$version_field]+1;
            if (1!=$this->allowField(true)->save($save_data,$map)){
                throw new \Exception("修改信息出错:".$this->getError());
            }

            return true;
    }


    /**
     * 判断字段是否存在
     * Power: Mikkle
     * Email：776329498@qq.com
     * @param $column
     * @param string $table
     * @return bool
     */
    protected function hasColumn($column,$table=""){
        $table = isset($table)?$table:$this->table;
        if (empty($table)||$column){
            $this->error="hasColumn方法参数缺失";
            return false;
        }
        $sql = "SELECT * FROM information_schema.columns WHERE table_schema=CurrentDatabase AND table_name = '{$table}' AND column_name = '{$column}'";
        return $this->query($sql) ? true : false;
    }

    public function getWithAlisaName(){
        return strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', (new \ReflectionClass(static::class))->getShortName()));
    }


//    /**得到基础条件
//     * @param $status
//     * @param null $model
//     * @param string $alisa
//     */
//    public  function getBaseWhere($whereData = [], $model = null, $alisa = '')
//    {
//        if (!$model) {
//            $model = new self;
//            if ($alisa) $model = $model->alias($alisa);
//        }
//        if ($alisa) $alisa = $alisa . '.';
//        $model = $model->where($whereData);
//        return $model;
//    }
//
//
//    /**
//     * 基础列表
//     */
//    public function getBaseList($whereData = [], $page = 0, $limit = 0, $sort = '',$field ="*",$where=[],$alisa = '')
//    {
//        if ($alisa) $alisa = $alisa . '.';
//        if(!$sort)$sort = "{$alisa}id desc";
//        $self = $this->getBaseWhere($whereData, null, $alisa)->where($where)->field($field);
//        if($page&&$limit)$self = $self->page($page, $limit);
//        $list = $self->orderRaw($sort)->select();
//        $count = $this->getBaseWhere($whereData, null, $alisa)
//            ->where($where)
//            ->count();
//        return compact('list', 'count','page','limit');
//    }




    /**
     * 获取时间段之间的model
     * @param int|string $time
     * @param string $ceil
     * @return array
     */
    public static function getModelTime($where, $model = null, $prefix = 'add_time', $data = 'data', $field = ' - ')
    {
        if ($model == null) $model = new self;
        if (!isset($where[$data])) return $model;
        switch ($where[$data]) {
            case 'today':
            case 'week':
            case 'month':
            case 'year':
            case 'yesterday':
                $model = $model->whereTime($prefix, $where[$data]);
                break;
            case 'quarter':
                list($startTime, $endTime) = self::getMonth();
                $model = $model->where($prefix, '>', strtotime($startTime));
                $model = $model->where($prefix, '<', strtotime($endTime));
                break;
            case 'lately7':
                $model = $model->where($prefix, 'between time', [strtotime("-7 day"), time()]);
                break;
            case 'lately30':
                $model = $model->where($prefix, 'between time', [strtotime("-30 day"), time()]);
                break;
            default:
                if (strstr($where[$data], $field) !== false) {
                    list($startTime, $endTime) = explode($field, $where[$data]);
                    $model = $model->where($prefix, '>', strtotime($startTime));
                    $model = $model->where($prefix, '<', bcadd(strtotime($endTime), 86400, 0));
                }
                break;
        }
        return $model;
    }


    /**
     * 获取本季度 time
     * @param int|string $time
     * @param string $ceil
     * @return array
     */
    public static function getMonth($time = '', $ceil = 0)
    {
        if ($ceil != 0)
            $season = ceil(date('n') / 3) - $ceil;
        else
            $season = ceil(date('n') / 3);
        $firstday = date('Y-m-01', mktime(0, 0, 0, ($season - 1) * 3 + 1, 1, date('Y')));
        $lastday = date('Y-m-t', mktime(0, 0, 0, $season * 3, 1, date('Y')));
        return array($firstday, $lastday);
    }


    /**
     * 加载语言文件
     * @param string $name
     */
    protected function loadlang($name=null)
    {
        if(!$name)$name = str_replace('model/', '', strstr(str_replace('\\', '/', $this->class), 'model/'));
        $name = Loader::parseName($name);
        $name_arr = explode('/',$name);
        $i = count($name_arr)-1;
        if($name_arr[$i][0]=='_')$name_arr[$i] = substr($name_arr[$i],1);
        $name = implode("/",$name_arr);
        Lang::load(APP_PATH . request()->module() . '/lang/' . request()->langset() . '/' . str_replace('.', '/', $name) . '.php');
    }




}