<?php
// +----------------------------------------------------------------------
// | HkCms 文章模型
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2021 http://www.hkcms.cn, All rights reserved.
// +----------------------------------------------------------------------
// | Author: 广州恒企教育科技有限公司 <admin@hkcms.cn>
// +----------------------------------------------------------------------

declare (strict_types=1);

namespace app\admin\model\cms;

use think\facade\Db;
use think\facade\Validate;
use think\Model;
use think\model\concern\SoftDelete;
use think\Paginator;

class Archives extends Model
{
    use SoftDelete;

    /**
     * 软删除字段
     * @var string
     */
    protected $deleteTime = 'delete_time';

    public static $tablename;

    /**
     * 指定自动时间戳类型
     * @var string
     */
    protected $autoWriteTimestamp = 'int';

    /**
     * 格式化发布日期
     * @param $value
     * @param $data
     * @return false|string
     */
    public function getPublishTimeTextAttr($value, $data)
    {
        return empty($data['publish_time']) ? '-' : date('Y-m-d H:i:s', $data['publish_time']);
    }

    /**
     * 格式化url
     * @param $value
     * @param $data
     * @return string
     */
    public function getUrlAttr($value, $data)
    {
        return $this->buildUrl($value, $data);
    }

    /**
     * 获取完整url地址
     * @param $value
     * @param $data
     * @return int|mixed|string|string[]
     */
    public function getFullurlAttr($value, $data)
    {
        return $this->buildUrl($data['url'], $data, true);
    }

    /**
     * 生成url地址
     * @param $value
     * @param $data
     * @param bool $domain
     */
    protected function buildUrl($value, $data, $domain = false)
    {
        if (empty($value)) {
            $cateInfo = Category::where(['id'=>$data['category_id']])->find();
            if (!$cateInfo) {
                return '';
            }
            $cateInfo = $cateInfo->toArray();
            $site = site(); // 获取伪静态规则
            if ($data['status']!='normal') {
                // 去到预览页
                $param = ['category_id'=>$data['category_id'],'id'=>$data['id']];
                if ($site['content_lang_on']==1) {
                    $param['lang'] = $data['lang'];
                }
                return (string) url('/cms.archives/preview',$param);
            }
            if ($site['url_mode']==1 && !empty($site['url_rewrite'])) {
                $cateInfo['aid'] = $data['id'];
                $param = $cateInfo;
            } else {
                $param = ['id'=>$data['id'],'catname'=>$cateInfo['name']];
                if ($site['content_lang_on']==1) {
                    $param['lang'] = $data['lang'];
                }
            }
            return index_url('/index/show', $param, '', $domain);
        } else if ($domain) {
            if (!\think\facade\Validate::regex($value, '/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?\//i')) {
                $value = app('request')->domain() . $value;
            }
        }
        return $value;
    }

    /**
     * 格式化
     * @param $value
     * @param $data
     * @return false|string
     */
    public function getDeleteTimeTextAttr($value, $data)
    {
        return empty($data['delete_time']) ? '-' : date('Y-m-d H:i:s', $data['delete_time']);
    }

    /**
     * save 方法下，新增，修改都会触发
     * @param Model $model
     * @return mixed|void
     */
    public static function onBeforeWrite($model)
    {
        $publishTime = $model->getData('publish_time');
        if (empty($publishTime)) {
            $model->setAttr('publish_time', time());
        } else if (!is_numeric($publishTime)) {
            $model->setAttr('publish_time', strtotime($publishTime));
        }

        $data = $model->getData();
        if (isset($data['flags'])) {
            $flags = explode(',', $data['flags']);
            if (in_array('top', $flags)) {
                $model->setAttr('weigh', 9999);
            } else if ($data['weigh']==9999) {
                $model->setAttr('weigh', 0);
            }
        }
    }

    /**
     * 查询后，使用与模型->select()/find()后执行save，保证表名称保持一致。
     * @param Model $model
     */
    public static function onAfterRead(Model $model)
    {
        if (!empty(self::$tablename)) {
            $model->name = $model->getName() != self::$tablename ? self::$tablename:$model->getName();
        }
    }

    /**
     * 获取栏目对应的表格信息
     * @param $categoryId
     * @param $categoryInfo
     * @return array|Model|null
     */
    public function getTableInfo($categoryId, &$categoryInfo=null)
    {
        if (empty($categoryId)) {
            abort(404, lang('%s not null',['category_id']));
        }
        $categoryInfo = Category::where(['id'=>$categoryId,'status'=>'normal'])->find();
        if (empty($categoryInfo)) {
            abort(404, lang('Column information does not exist'));
        }
        $modelInfo = \app\admin\model\cms\Model::where(['status'=>'normal', 'id'=>$categoryInfo['model_id']])->find();
        if (empty($modelInfo)) {
            abort(404, lang('Model information does not exist'));
        }
        return $modelInfo;
    }

    /**
     * 无需表前缀, 定义表名称
     * @param $name
     * @return $this
     */
    public function setTable($name)
    {
        $this->name = $name;
        self::$tablename = $name;
        return $this;
    }

    /**
     * 固定方法，用于栏目删除后的处理
     * @param $modelInfo
     * @param $categoryId
     * @param int $force 1=分类放入回收站，2=还原，3=销毁
     */
    public function handleDel($modelInfo, $categoryId, $force=1)
    {
        if ($force==3) {
            $ids = \think\facade\Db::name($modelInfo['tablename'])->where(['category_id'=>$categoryId])->where('delete_time','not null')->column('id');
            \think\facade\Db::name($modelInfo['tablename'])->where(['category_id'=>$categoryId])->where('delete_time','not null')->delete();
            if ($modelInfo['type']=='more' && $modelInfo['allow_single']!=1) {
                \think\facade\Db::name($modelInfo['tablename'].'_data')->whereIn('id',$ids)->delete();
            }
        } else if ($force == 2) {
            (new Archives)->onlyTrashed()->name($modelInfo['tablename'])->where(['category_id'=>$categoryId])->update(['delete_time'=>null]);
        } else {
            (new Archives)->setTable($modelInfo['tablename'])->where(['category_id'=>$categoryId])->update(['delete_time'=>time()]);
        }
    }

    /**
     * 获取列表，用于内容标签
     * @param $tag
     * @param $page \think\Paginator|mixed paginate 分页对象
     * @return array|mixed|object|\think\App
     */
    public function tagContent($tag, &$page)
    {
        $tag['order'] = !empty($tag['order']) ? $tag['order'] : '';
        $tag['flag'] = !empty($tag['flag']) ? $tag['flag'] : '';
        $sqlStr = ''; // 字符拼接查询

        // 语言切换
        $tag['lang'] = site('content_lang');
        if (site('content_lang_on')==1) {
            $tag['lang'] = app()->lang->getLangSet();
        }
        // 获取请求的排序、数据筛选
        $param = app()->request->get();
        $sort = app()->request->get('sort');
        $order = app()->request->get('order');
        if ($sort!='_default' && Validate::is($sort, 'alphaDash')) {
            $mf = ModelField::where(['field_name'=>$sort])->cache()->find();
            if (!empty($mf)) {
                $tag['more'] = isset($tag['more']) && $tag['more'] == 1?$tag['more']:($mf->iscore==1?0:1);
                $tag['order'] = [($mf->iscore==1?'':'x.').$sort=>$order=='desc'?$order:'asc'];
            }
        }
        $filter = array_diff_key($param, array_flip(['sort','order','lang']));

        // 获取操作的表
        if (empty($tag['model']) || !is_numeric($tag['model'])) {
            $cateInfo = Category::where(['id'=>$tag['catid'],'status'=>'normal','lang'=>$tag['lang']])->cache()->find();
            if (empty($cateInfo['model_id'])) {
                return [];
            }
            $tag['model'] = $cateInfo['model_id'];
        }
        $modelInfo = \app\admin\model\cms\Model::where(['status'=>'normal','id'=>$tag['model']])->cache()->find();
        if (empty($modelInfo)) {
            return [];
        }

        // 默认条件
        $map = [['status','=','normal'],['lang','=',$tag['lang']]];
        $filterField = ModelField::where(['model_id'=>$tag['model'],'is_filter'=>1])->cache(true)->select()->toArray();
        foreach ($filterField as $key=>$value) {
            if (isset($filter[$value['field_name']]) && $filter[$value['field_name']]!='') {
                $tempArr = explode(',', $filter[$value['field_name']]);
                // 匹配是否是筛选的值
                $setting = json_decode($value['setting'], true);
                if (!empty($setting['filter_option'])) {
                    $option = json_decode($setting['filter_option'], true);
                } else if (!empty($value['data_list'])) {
                    $option = $value['data_list'];
                }
                if (!empty($option)) {
                    $option = array_flip($option);
                    foreach ($tempArr as $k=>$v) {
                        if (!in_array($v,$option)) {
                            unset($tempArr[$k]);
                        }
                    }
                    if (count($tempArr)>1) {
                        // 有副表筛选字段时，启用副表连接
                        $tag['more'] = isset($tag['more']) && $tag['more'] == 1?$tag['more']:($value['iscore']==1?0:1);
                        $map[] = [($value['iscore']!=1?'x.':'').$value['field_name'],'in',implode(',',$tempArr)];
                        $param = array_merge($param, [$value['field_name']=>implode(',',$tempArr)]);
                    } else if (count($tempArr)==1) {
                        $tag['more'] = isset($tag['more']) && $tag['more'] == 1?$tag['more']:($value['iscore']==1?0:1);
                        $map[] = [($value['iscore']!=1?'x.':'').$value['field_name'],'=',$tempArr[0]];
                        $param = array_merge($param, [$value['field_name']=>$tempArr[0]]);
                    }
                }
            }
        }

        // 对ID重名字段加别名区分
        if (!empty($tag['more']) && $tag['more']==1 && $modelInfo['type']=='more' && $modelInfo['allow_single']!=1 && empty($tag['order'])) { // 副表
            $tag['order'] = 'weigh desc,a.id desc';
        } else if (empty($tag['order'])) {
            $tag['order'] = 'weigh desc,id desc';
        } else if (!empty($tag['order']) && is_string($tag['order']) && $tag['more']==1 && $modelInfo['type']=='more' && $modelInfo['allow_single']!=1) {
            $sortArr = explode(',',$tag['order']);
            foreach ($sortArr as &$vo) {
                $vo = stripos($vo, "id ")===0 ? 'a.'.$vo : $vo;
            }
            $tag['order'] = implode(',', $sortArr);
        }

        // 检查条件字段是否加了id
        if (!empty($tag['where']) && is_string($tag['where']) && $tag['more']==1 && $modelInfo['type']=='more' && $modelInfo['allow_single']!=1) {
            $sortArr = explode(' ',$tag['where']);
            foreach ($sortArr as &$item) {
                $item = stripos($item, "id=")===0 ? 'a.'.$item : $item;
            }
            $tag['where'] = implode(' ', $sortArr);
        }

        // 增加缓存非分页数据
        if (!$tag['page']) {
            $cacheID = to_guid_string($tag);
            if (!env('APP_DEBUG') && $cacheData = cache($cacheID)) {
                return $cacheData;
            }
        }

        // 获取栏目ID，包含下级。
        if (!empty($tag['catid']) && is_numeric($tag['catid']) && $tag['insub']==1) {
            $catIdArr = get_category_sub($tag['catid'], false, ['status'=>'normal','model_id'=>$tag['model']]);
            if (!empty($catIdArr)) {
                $catIdArr[] = $tag['catid'];
                $map[] = ['category_id','in',$catIdArr];
            } else {
                $map[] = ['category_id','=',$tag['catid']];
            }
        } else if (!empty($tag['catid']) && is_numeric($tag['catid']) && $tag['insub']==0) {
            $map[] = ['category_id','=',$tag['catid']];
        }

        // 文档属性
        if (!empty($tag['flag'])) {
            $sql = [];
            if (stripos($tag['flag'], ' and ')) {
                $flag = explode(' and ', $tag['flag']);
                foreach ($flag as $key=>$val) {
                    $sql[] = "find_in_set('{$val}',flags)";
                }
                if ($sql) {
                    $sql = implode(' and ', $sql);
                }
            } else if (stripos($tag['flag'], ' or ')) {
                $flag = explode(' or ', $tag['flag']);
                foreach ($flag as $key=>$val) {
                    $sql[] = "find_in_set('{$val}',flags)";
                }
                if ($sql) {
                    $sql = "(".implode(' or ', $sql).")";
                }
            } else {
                $sql = "find_in_set('{$tag['flag']}',flags)";
            }
            $sqlStr = !empty($sqlStr) ? $sqlStr.' and '.$sql : $sql;
        }

        if ($tag['page'] && empty($tag['tagid'])) { // 开启分页
            if (!empty($tag['more']) && $tag['more']==1 && $modelInfo['type']=='more' && $modelInfo['allow_single']!=1) { // 副表
                $obj = $this->setTable($modelInfo->tablename)->alias('a')
                    ->with(['category','model'])
                    ->join($modelInfo->tablename.'_data x','a.id=x.id','LEFT')
                    ->where($map)
                    ->where($tag['where'])
                    ->where($sqlStr)
                    ->order($tag['order'])
                    ->append(['publish_time_text','fullurl'])
                    ->paginate([
                        'list_rows'=> intval($tag['num']),
                        'var_page' => 'page',
                        'query' => $param,
                        'path'=>'/index/lists'
                    ], false);
            } else {
                $obj = $this->setTable($modelInfo->tablename)
                    ->with(['category','model'])
                    ->where($map)
                    ->where($tag['where'])
                    ->where($sqlStr)
                    ->order($tag['order'])
                    ->append(['publish_time_text','fullurl'])
                    ->paginate([
                        'list_rows'=> intval($tag['num']),
                        'var_page' => 'page',
                        'query' => $param,
                        'path'=>'/index/lists'
                    ], false);
            }
            $array = $obj->toArray()['data'];
            $page = $obj;
        } else if ($tag['page'] && !empty($tag['tagid'])) { // 瀑布流分页
            $page = Paginator::getCurrentPage('page');
            if (!empty($tag['more']) && $tag['more']==1 && $modelInfo['type']=='more' && $modelInfo['allow_single']!=1) { // 副表
                $obj = $this->setTable($modelInfo->tablename)->alias('a')
                    ->with(['category','model'])
                    ->join($modelInfo->tablename.'_data x','a.id=x.id','LEFT')
                    ->where($map)
                    ->where($tag['where'])
                    ->where($sqlStr)
                    ->order($tag['order'])
                    ->append(['publish_time_text','fullurl'])
                    ->page($page, intval($tag['num']))
                    ->select();
                $array = $obj->toArray();
            } else {
                $obj = $this->setTable($modelInfo->tablename)
                    ->with(['category','model'])
                    ->where($map)
                    ->where($tag['where'])
                    ->where($sqlStr)
                    ->order($tag['order'])
                    ->append(['publish_time_text','fullurl'])
                    ->page($page, intval($tag['num']))
                    ->select();
                $array = $obj->toArray();
            }

            $tag['key'] = md5($tag["tagid"]);
            $total = cache($tag['key']);
            if (empty($total['total'])) {
                // 数量
                $total = $this->setTable($modelInfo->tablename)
                    ->where($map)
                    ->where($tag['where'])
                    ->where($sqlStr)
                    //->order($tag['order'])
                    ->count();
            } else {
                $total = $total['total'];
            }
            $tag['total'] = $total;
            $page = $tag;
            $page['map_param'] = $param;
            cache($tag['key'],$page);
        } else { // 不分页
            // 限制结果
            $offset = 0;
            $length = null;
            if (!empty($tag['num']) && is_numeric($tag['num']) && $tag['num']>0) { // 指定分页
                $offset = intval($tag['num']);
            } else if (!empty($tag['num']) && strpos($tag['num'], ',') !== false) {
                $temp = explode(',', $tag['num']);
                if (count($temp)==2 && is_numeric($temp[0]) && is_numeric($temp[1])) {
                    $offset = (int)$temp[0]-1;
                    $length = (int)$temp[1];
                }
            }

            if (!empty($tag['more']) && $tag['more']==1 && $modelInfo['type']=='more' && $modelInfo['allow_single']!=1) { // 副表
                $array = $this->setTable($modelInfo->tablename)->alias('a')
                    ->with(['category','model'])
                    ->join($modelInfo->tablename.'_data x','a.id=x.id','LEFT')
                    ->where($map)
                    ->where($tag['where'])
                    ->where($sqlStr)
                    ->order($tag['order'])
                    ->limit($offset,$length)
                    ->append(['publish_time_text','fullurl'])
                    ->select()->toArray();
            } else {
                $array = $this->setTable($modelInfo->tablename)
                    ->with(['category','model'])
                    ->where($map)
                    ->where($tag['where'])
                    ->where($sqlStr)
                    ->order($tag['order'])
                    ->limit($offset,$length)
                    ->append(['publish_time_text','fullurl'])
                    ->select()->toArray();
            }
        }

        // 获取扩展字段
        $fields = \think\facade\Db::name('model_field')->where(['status'=>'normal','model_id'=>$modelInfo->id])->cache()->select()->toArray();
        // 字段格式化
        foreach ($array as $key=>$value) {
            foreach ($fields as $k=>$v) {
                field_format($v, $array[$key]);
                // 兼容旧版
                if ($v['iscore']!=1 && !empty($tag['more']) && $tag['more']==1 && $modelInfo['type']=='more' && $modelInfo['allow_single']!=1) {
                    $array[$key]['more'][$v['field_name']] = $array[$key][$v['field_name']];
                }
            }
        }

        if (!$tag['page']) {
            // 结果进行缓存
            if (!env('APP_DEBUG')) {
                // 缓存设置
                $cacheTime = !empty($tag['cache']) && is_numeric($tag['cache']) ? intval($tag['cache']) : 3600;
                cache($cacheID, $array, $cacheTime);
            }
        }
        return $array;
    }

    /**
     * 用于获取单条标签
     * @param $tag
     * @param $model
     * @return array
     */
    public function tagArcone($tag, $model)
    {
        if (empty($tag['aid']) || !is_numeric($tag['aid'])) {
            return [];
        }

        $cacheTime = !empty($tag['cache']) && is_numeric($tag['cache']) ? intval($tag['cache']) : 3600;

        if (!empty($tag['more']) && $tag['more']==1 && $model['type']=='more' && $model['allow_single']!=1) { // 副表
            $info = $this->setTable($model->tablename)->alias('a')
                ->with(['category','model'])
                ->join($model->tablename.'_data x','a.id=x.id','LEFT')
                ->where('x.id',$tag['aid']);
        } else {
            $info = $this->setTable($model->tablename)
                ->with(['category','model'])
                ->where('id',$tag['aid']);
        }

        if (!env('APP_DEBUG')) {
            $info = $info->cache($cacheTime);
        }

        $info = $info->append(['publish_time_text','url'])->find();
        if (empty($info)) {
            return [];
        }

        $array = [$info->toArray()];
        // 获取扩展字段
        $fields = \think\facade\Db::name('model_field')->where(['status'=>'normal','model_id'=>$model->id])->cache()->select()->toArray();
        // 字段格式化
        foreach ($array as $key=>$value) {
            foreach ($fields as $k=>$v) {
                field_format($v, $array[$key]);
                // 兼容旧版
                if ($v['iscore']!=1 && !empty($tag['more']) && $tag['more']==1 && $model['type']=='more' && $model['allow_single']!=1) {
                    $array[$key]['more'][$v['field_name']] = $array[$key][$v['field_name']];
                }
            }
        }

        return $array;
    }

    /**
     * 栏目相对关联
     * @return \think\model\relation\BelongsTo
     */
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * 模型相对关联
     * @return Archives|\think\model\relation\BelongsTo
     */
    public function model()
    {
        return $this->belongsTo(\app\admin\model\cms\Model::class);
    }

    /**
     * 关联副表
     * @return \think\model\relation\HasOne
     */
    public function moreInfo()
    {
        \app\admin\model\cms\ArchivesX::$tablename = self::$tablename.'_data';
        return $this->hasOne(\app\admin\model\cms\ArchivesX::class,'id','id');
    }
}