cms-manage/app/controller/backend/CategoryController.php

496 lines
20 KiB
PHP

<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\exception\ModelException;
use app\model\Attachment;
use app\model\Category;
use app\model\CategoryCheck;
use app\model\Route;
use app\model\ThemeFile;
use app\model\Website;
use app\service\ApiService;
use app\service\CacheService;
use app\service\CategoryService;
use app\service\StaticFileService;
use app\validate\CategoryValidate;
use Overtrue\Pinyin\Pinyin;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Lang;
class CategoryController extends BaseController
{
protected $cacheKeyArr = 'hc_module_cate_arr';
/**
* 栏目列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function index(Category $category): \think\response\Json
{
$websiteId = (int)input('param.website_id');
if(!$websiteId){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$where = [
['seller_id','=', $this->admin['seller_id']],
['website_id','=',$websiteId],
];
$lang = input('lang');
if(empty($lang)){
$lang = config('lang.default_lang');
}
$Website = new Website();
$website = $Website -> getCustomArrayData(['id'=>$websiteId,'seller_id'=>$this->admin['seller_id']])['data'];
$domain = $website['domain'];
if($lang != config('lang.default_lang')){
$domain = $domain .'/'.$lang;
}
$title = $this->request->param('title','');
if(!empty($title)) {
$where[] = ['title', 'like', '%' . $title . '%'];
}
$where[] = ['lang','=',$lang];
$with = [
'thumbnail' => function($query){
$query->field('id,name,url');
}
];
//栏目管理搜索栏目名称
$categoryTitle = $this->request->param("category_title/s",'','trim,strip_tags');
if(!empty($categoryTitle)){
$categoryIdPath = $category->where([
['seller_id','=', $this->admin['seller_id']],
['website_id','=',$websiteId],
['lang','=',$lang],
['title','like',"%{$categoryTitle}%"],
])->column('path','id');
if(empty($categoryIdPath)){
return jsonReturn(0,'内容不存在');
}
$selectIds = [];
foreach ($categoryIdPath as $pathId => $paths){
$paths = explode('-',$paths);
for ($i=1;$i<count($paths)-1;$i++){
$selectIds[$paths[$i]] = $paths[$i];
}
$selectIds[$pathId] = $pathId;
}
$where[] = ['id','in',$selectIds];
}
$themeFileModel = new ThemeFile();
$designFileList = $themeFileModel->getAllCustomArrayData([['is_design', '=', 1]])['data'];
$newDesignFileList = [];
foreach ($designFileList as $value) {
$value['file_name'] = str_replace('.html', '', $value['file']);
$newDesignFileList[$value['file']] = $value;
$newDesignFileList[$value['file_name']] = $value;
}
$categoryList = $category->getAllCustomArrayData($where,'id asc','id,seller_id,parent_id,title,lang,alias,type,path,thumbnail,sort,status,list_tpl',$with)['data'];
foreach($categoryList as &$item){
if($item['type'] == 1 || $item['type'] == 4){
if(!empty($item['alias'])){
if($item['alias'] == '/'){
$item['fullUrl'] = '//' . $domain;
}else{
$item['fullUrl'] = '//' . $domain . $item['alias'].'.'.config('route.url_html_suffix');
}
}else{
$item['fullUrl'] = '//' . $domain . '/list/index/'.$item['id'].'.'.config('route.url_html_suffix');
}
}else if($item['type'] == 3){
$item['fullUrl'] = $item['alias'];
}else{
$item['fullUrl'] = 'javascript:;';
}
$item['is_design'] = 0;
$item['design_path'] = '';
if (isset($newDesignFileList[$item['list_tpl']])) {
$item['is_design'] = 1;
$item['design_path'] = $newDesignFileList[$item['list_tpl']]['design_path'];
}
}
$categoryList = makeTree($categoryList);
return jsonReturn(0,'success',$categoryList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function save(CategoryService $categoryService,Category $Category): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['alias'] = $param['alias'] ?? '';
$param['module_id'] = $param['module_id'] ?? 1;
// 数据验证
try{
if(!empty($param['parent_map'])){
$param = $this->getMapCateData($param);
}
validate(CategoryValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
if (in_array($param['alias'], StaticFileService::$forbidNames)) {
return jsonReturn(-2,lang('别名已被系统占用,请修改别名'));
}
$param['seller_id'] = $this->admin['seller_id'];
$category = $Category->existCategory(['title'=>$param['title'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang'],'parent_id'=>$param['parent_id']])['data'];
if(!empty($category)){
return jsonReturn(-2,'栏目已经存在');
}
if(in_array($param['type'],[1,4]) && empty($param['alias'])){
if($param['list_tpl'] == 'index'){
$param['alias'] = '/';
}else{
$param['alias'] = $this->getAlias($param['title'],$param['website_id'],$param['lang'],$param['seller_id']);
}
}
if(!empty($param['alias']) && $param['alias'] != 'javascript:;'){
$category = $Category->existCategory(['title'=>$param['alias'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang']])['data'];
}
if(!empty($category)){
return jsonReturn(-3,lang('栏目别名已经存在'));
}
if ($param['need_check'] == 1 && (empty($param['check_list']) || !is_array($param['check_list']))) {
return jsonReturn(-3,'请设置审核人员!');
}
if (!empty($param['field_list'])) {
$keyArr = [];
foreach ($param['field_list'] as $value) {
if (isset($keyArr[$value['key']])) {
return jsonReturn(-5,lang('自定义字段名称重复:') . $value['key']);
}
$keyArr[$value['key']] = $value;
}
$param['field_list'] = json_encode($param['field_list'], JSON_UNESCAPED_UNICODE);
}
return $categoryService -> createCategory($param);
}
return jsonReturn(-3,Lang::get(lang('请求方法错误')));
}
/**
* 栏目详情
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(Category $category,Attachment $attachment): \think\response\Json
{
$param = input('param.');
try {
validate(CategoryValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['seller_id']= $this->admin['seller_id'];
$with = [
'thumbnail' => function($query){
$query->field('id,name,url');
},'banner' => function($query){
$query->field('id,name,url');
}
];
$res = $category->getCategory($param,$with);
if (!empty($res['data']['content'])) {
$res['data']['content'] = htmlspecialchars_decode($res['data']['content']);
}
$res['data']['check_list'] = [];
if ($res['data']['need_check'] == 1) {
$checkModel = new CategoryCheck();
$checkList = $checkModel->where([
['category_id', '=', $res['data']['id']],
['status', '=', 1]
])->select()->toArray();
$res['data']['check_list'] = $checkList;
}
if (!empty($res['data']['field_list'])) {
$res['data']['field_list'] = json_decode($res['data']['field_list'], true);
}
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function update(CategoryService $categoryService,Category $Category): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
if(!empty($param['parent_map'])){
$param = $this->getMapCateData($param);
}
validate(CategoryValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
if (in_array($param['alias'], StaticFileService::$forbidNames)) {
return jsonReturn(-2,lang('别名已被系统占用,请修改别名'));
}
$param['seller_id'] = $this->admin['seller_id'];
if(in_array($param['type'],[1,4]) && empty($param['alias'])){
if($param['list_tpl'] == 'index'){
$param['alias'] = '/';
}else{
$param['alias'] = $this->getAlias($param['title'],$param['website_id'],$param['lang'],$param['seller_id']);
}
}
$category = $Category->existCategory(['title'=>$param['title'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang'],'parent_id'=>$param['parent_id']])['data'];
if(!empty($category) && $category['id'] != $param['id']){
return jsonReturn(-2,lang('栏目已经存在'));
}
$category = $Category->existCategory(['title'=>$param['alias'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id']])['data'];
if(!empty($category) && $category['id'] != $param['id']){
return jsonReturn(-3,lang('栏目别名已经存在'));
}
if (isset($param['need_check']) && $param['need_check'] == 1 && (empty($param['check_list']) || !is_array($param['check_list']))) {
return jsonReturn(-3,lang('请设置审核人员'));
}
if (!empty($param['field_list'])) {
$keyArr = [];
foreach ($param['field_list'] as $value) {
if (isset($keyArr[$value['key']])) {
return jsonReturn(-5,lang('自定义字段名称重复:') . $value['key']);
}
$keyArr[$value['key']] = $value;
}
$param['field_list'] = json_encode($param['field_list'], JSON_UNESCAPED_UNICODE);
}
$this->deleteCateCacheKey($param['website_id'],$param['lang']);
return $categoryService -> updateCategory($param);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除栏目
* @param Category $category
* @param Route $route
* @return \think\response\Json
*/
public function delete(Category $category,Route $route): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(CategoryValidate::class)->scene('delete')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'lang' => $param['lang']
];
Db::startTrans();
try {
$subCate = $category -> getAllCustomArrayData(['seller_id'=>$this->admin['seller_id'],'parent_id'=>$param['id']])['data'];
$this->deleteCateCacheKey($param['website_id'],$param['lang']);
if(!empty($subCate)){
return jsonReturn(-1,lang('栏目下面有子栏目,不能直接删除'));
}
$res = $category->delCategory($where);
$route->delRoute(['seller_id' => $this->admin['seller_id'],'category_id'=>$param['id']]);
$route->getRoutes($param['website_id'], $this->admin['seller_id'], $param['lang']);
CacheService::deleteRelationCacheByObject($route);
CacheService::deleteRelationCacheByObject($category);
$optAdmin = request()->admin;
event("AdminOptLog",[
'admin_id' => $optAdmin['uid'],
'admin_name' => $optAdmin['name'],
'title'=>lang("栏目管理"),
"content"=>lang("删除栏目,栏目ID为").$param['id'],
]);
Db::commit();
Cache::clear();
}catch (ModelException $me){
Db::rollback();
return jsonReturn(50023,$me->getMessage());
}catch (\Exception $e){
Db::rollback();
return jsonReturn(50024,$e->getMessage());
}
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 分组获取栏目列表
* @param Category $Category
* @return \think\response\Json
*/
public function getModuleCate(Category $Category): \think\response\Json
{
$param = input('get.');
try {
validate(CategoryValidate::class)->scene('getModuleCate')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$Website = new Website();
$website = $Website->getAllCustomArrayData([['id','in',$param['site_id']],['seller_id','=',$this->admin['seller_id']]]
,'id asc','id,seller_id,title,domain')['data'];
$website = getColumnForKeyArray($website,'id');
$category = $Category -> getAllCustomArrayData([['website_id','in',$param['site_id']],['seller_id','=',$this->admin['seller_id']],['lang','=',$param['lang']]],'id asc')['data'];
$category = getArrayGroupBy($category,'website_id');
$response = [];
foreach($category as $key => $cate){
$tmpCategory = $this->makeTree($cate);
$tmpCategory = $this->imp($tmpCategory);
$tmpCate = $website[$key];
$tmpCate['category'] = $tmpCategory;
$response[] = $tmpCate;
}
return jsonReturn(0,lang('成功'),$response);
}
public function makeTree($data, int $pid=0, int $level=0): array
{
$tree = array();
$tmpTree = [];
foreach ($data as $key => &$value) {
$str = str_repeat('--',$level);
$value['title'] = $str . $value['title'];
if ($value['parent_id'] == $pid) {
$value['level'] = $level;
unset($data[$key]);
$tmpTree[] = $value;
$value['children'] = $this->makeTree($data, $value['id'],$level+1);
$tree[] = $value;
}else{
$tmpTree[] = $value;
}
}
return $tree;
}
public function imp($tree, $children='children'): array
{
$impArr = array();
foreach($tree as $w) {
if(isset($w[$children])) {
$t = $w[$children];
unset($w[$children]);
$impArr[] = $w;
if(is_array($t)) $impArr = array_merge($impArr, $this->imp($t, $children));
} else {
$impArr[] = $w;
}
}
return $impArr;
}
/**
* 栏目复制
* @throws ModelException
* @throws \Exception
*/
public function copy(CategoryService $categoryService): \think\response\Json
{
set_time_limit(300);
$param = input('post.');
try {
validate(CategoryValidate::class)->scene('copy')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
foreach ($param['target_site'] as $val){
if(empty($val) || !is_numeric($val)){
return jsonReturn(-1,lang('目标站点数据异常,请检查'));
}
}
$res = $categoryService -> copyCate($param['original_site'],$param['target_site'],$param['lang'],$this->admin['seller_id']);
return json($res);
}
/**
* @throws \app\exception\ModelEmptyException
* @throws ModelException
*/
public function getMapCateData(&$param)
{
$Category = new Category();
$param['parent_path'] = json_encode($param['parent_map']);
$param['parent_map'] = array_pop($param['parent_map']);
$mapCate = $Category->getCategory(['id'=>$param['parent_map'],'seller_id'=>$this->admin['seller_id']])['data']->toArray();
foreach($mapCate as $k => $v){
if($k == 'parent_id'){
continue;
}
if(empty($param[$k]) && !in_array($k,['id','create_time','update_time'])){
$param[$k] = $v;
}
}
return $param;
}
public function deleteCateCacheKey($siteId,$lang)
{
$cateCacheKey = 'hc_cate_' . $this->admin['seller_id'] . '_' . $siteId .'_' . $lang;
Cache::delete($cateCacheKey);
$moduleCateArr = Cache::get($this->cacheKeyArr);
if(!empty($moduleCateArr)){
foreach ($moduleCateArr as $cate){
$tmpCate = explode('_',str_replace('hc_module_cate_' . $this->admin['seller_id'] . '_' . $lang .'_','',$cate));
if(in_array($siteId,$tmpCate)){
$moduleCateCacheKey = 'hc_module_cate_' . $this->admin['seller_id'] . '_' . $lang .'_' . $siteId;
Cache::delete($moduleCateCacheKey);
unset($moduleCateArr[$cate]);
}
}
Cache::set($this->cacheKeyArr,$moduleCateArr);
}
}
/**
* @throws ModelException
* @throws \app\exception\ModelEmptyException
*/
public function getAlias($title, $siteId, $lang, $sellerId): string
{
$pinyin = new Pinyin();
$cacheKey = $sellerId .'_'.$siteId .'_'. $lang . '_website_cache_key';
$settingData = Cache::get($cacheKey);
if(empty($settingData)){
$settingData = ApiService::setWebsiteSetting($sellerId,$siteId,$lang);
}
if(!empty($settingData['alias_rule']) && $settingData['alias_rule'] == 1){
$alias = strtolower('/' . $pinyin -> abbr($title));
}else{
$alias = strtolower('/' . $pinyin -> permalink($title,''));
}
return $alias;
}
}