|
|
<?php
|
|
|
// +----------------------------------------------------------------------
|
|
|
// | OneThink [ WE CAN DO IT JUST THINK IT ]
|
|
|
// +----------------------------------------------------------------------
|
|
|
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
|
|
|
// +----------------------------------------------------------------------
|
|
|
// | Author: huajie <banhuajie@163.com>
|
|
|
// +----------------------------------------------------------------------
|
|
|
|
|
|
namespace Admin\Model;
|
|
|
use Think\Model;
|
|
|
use Admin\Model\AuthGroupModel;
|
|
|
|
|
|
/**
|
|
|
* 文档基础模型
|
|
|
*/
|
|
|
class DocumentModel extends Model{
|
|
|
|
|
|
/* 自动验证规则 */
|
|
|
protected $_validate = array(
|
|
|
array('title', 'require', '标题不能为空', self::MUST_VALIDATE, 'regex', self::MODEL_BOTH),
|
|
|
array('title', '1,80', '标题长度不能超过80个字符', self::MUST_VALIDATE, 'length', self::MODEL_BOTH),
|
|
|
array('name', '/^[a-zA-Z]\w{0,39}$/', '文档标识不合法', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH),
|
|
|
array('name', 'checkName', '标识已经存在', self::VALUE_VALIDATE, 'callback', self::MODEL_BOTH),
|
|
|
array('cover_id', 'require', '封面不能为空', self::EXISTS_VALIDATE, 'regex', self::MODEL_BOTH),
|
|
|
array('cover_id2', 'require', '封面图2不能为空', self::EXISTS_VALIDATE, 'regex', self::MODEL_BOTH),
|
|
|
array('cover_id2', '/^[1-9]\d*$/', '封面图2不能为空', self::EXISTS_VALIDATE, 'regex', self::MODEL_BOTH),
|
|
|
array('level', '/^[\d]+$/', '优先级只能填正整数', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH),
|
|
|
array('description', '1,140', '简介长度不能超过140个字符', self::VALUE_VALIDATE, 'length', self::MODEL_BOTH),
|
|
|
array('category_id', 'require', '分类不能为空', self::MUST_VALIDATE , 'regex', self::MODEL_INSERT),
|
|
|
array('category_id', 'require', '分类不能为空', self::EXISTS_VALIDATE , 'regex', self::MODEL_UPDATE),
|
|
|
array('category_id', 'check_category', '该分类不允许发布内容', self::EXISTS_VALIDATE , 'function', self::MODEL_UPDATE),
|
|
|
array('category_id,type', 'check_category', '内容类型不正确', self::MUST_VALIDATE, 'function', self::MODEL_INSERT),
|
|
|
array('model_id,pid,category_id', 'check_category_model', '该分类没有绑定当前模型', self::MUST_VALIDATE , 'function', self::MODEL_INSERT),
|
|
|
);
|
|
|
|
|
|
/* 自动完成规则 */
|
|
|
protected $_auto = array(
|
|
|
array('uid', 'is_login', self::MODEL_INSERT, 'function'),
|
|
|
array('title', 'htmlspecialchars', self::MODEL_BOTH, 'function'),
|
|
|
array('description', 'htmlspecialchars', self::MODEL_BOTH, 'function'),
|
|
|
array('root', 'getRoot', self::MODEL_BOTH, 'callback'),
|
|
|
array('link_id', 'getLink', self::MODEL_BOTH, 'callback'),
|
|
|
array('attach', 0, self::MODEL_INSERT),
|
|
|
array('view', 0, self::MODEL_INSERT),
|
|
|
array('comment', 0, self::MODEL_INSERT),
|
|
|
array('extend', 0, self::MODEL_INSERT),
|
|
|
array('create_time', 'getCreateTime', self::MODEL_BOTH,'callback'),
|
|
|
array('update_time', NOW_TIME, self::MODEL_BOTH),
|
|
|
array('status', 'getStatus', self::MODEL_BOTH, 'callback'),
|
|
|
array('position', 'getPosition', self::MODEL_BOTH, 'callback'),
|
|
|
array('deadline', 'strtotime', self::MODEL_BOTH, 'function'),
|
|
|
);
|
|
|
|
|
|
/**
|
|
|
* 获取详情页数据
|
|
|
* @param integer $id 文档ID
|
|
|
* @return array 详细数据
|
|
|
*/
|
|
|
public function detail($id){
|
|
|
/* 获取基础数据 */
|
|
|
$info = $this->field(true)->find($id);
|
|
|
if(!(is_array($info) || 1 !== $info['status'])){
|
|
|
$this->error = '文档被禁用或已删除!';
|
|
|
return false;
|
|
|
}
|
|
|
if(!empty($info['cover_id'])) {
|
|
|
$valueArr = explode(',', $info['cover_id']);
|
|
|
$str = '';
|
|
|
foreach ($valueArr as $key1 => $value1) {
|
|
|
$a = get_cover($value1, 'path');
|
|
|
$str .= $a.',';
|
|
|
}
|
|
|
$info['valuedata'] = rtrim($str, ',');
|
|
|
}
|
|
|
if(!empty($info['cover_id2'])) {
|
|
|
$valueArr = explode(',', $info['cover_id2']);
|
|
|
$str = '';
|
|
|
foreach ($valueArr as $key1 => $value1) {
|
|
|
$a = get_cover($value1, 'path');
|
|
|
$str .= $a.',';
|
|
|
}
|
|
|
|
|
|
$info['valuedata'] = rtrim($str, ',');
|
|
|
}
|
|
|
|
|
|
/* 获取模型数据 */
|
|
|
$logic = $this->logic($info['model_id']);
|
|
|
$detail = $logic->detail($id); //获取指定ID的数据
|
|
|
if(!$detail){
|
|
|
$this->error = $logic->getError();
|
|
|
return false;
|
|
|
}
|
|
|
$info = array_merge($info, $detail);
|
|
|
return $info;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 新增或更新一个文档
|
|
|
* @param array $data 手动传入的数据
|
|
|
* @return boolean fasle 失败 , int 成功 返回完整的数据
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
public function update($data = null){
|
|
|
/* 检查文档类型是否符合要求 */
|
|
|
$res = $this->checkDocumentType( I('type',2), I('pid') );
|
|
|
if(!$res['status']){
|
|
|
$this->error = $res['info'];
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/* 获取数据对象 */
|
|
|
$data = $this->token(false)->create($data);
|
|
|
if(empty($data)){
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/* 添加或新增基础内容 */
|
|
|
if(empty($data['id'])){ //新增数据
|
|
|
$id = $this->add(); //添加基础内容
|
|
|
if(!$id){
|
|
|
$this->error = '新增基础内容出错!';
|
|
|
return false;
|
|
|
}
|
|
|
} else { //更新数据
|
|
|
$status = $this->save(); //更新基础内容
|
|
|
if(false === $status){
|
|
|
$this->error = '更新基础内容出错!';
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 添加或新增扩展内容 */
|
|
|
$logic = $this->logic($data['model_id']);
|
|
|
$logic->checkModelAttr($data['model_id']);
|
|
|
if(!$logic->update($id)){
|
|
|
if(isset($id)){ //新增失败,删除基础数据
|
|
|
$this->delete($id);
|
|
|
}
|
|
|
$this->error = $logic->getError();
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
hook('documentSaveComplete', array('model_id'=>$data['model_id']));
|
|
|
|
|
|
//行为记录
|
|
|
if($id){
|
|
|
action_log('add_document', 'document', $id, UID);
|
|
|
}
|
|
|
|
|
|
//内容添加或更新完成
|
|
|
return $data;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取数据状态
|
|
|
* @return integer 数据状态
|
|
|
*/
|
|
|
protected function getStatus(){
|
|
|
$id = I('post.id');
|
|
|
if(empty($id)){ //新增
|
|
|
$cate = I('post.category_id');
|
|
|
$check = M('Category')->getFieldById($cate,'check');
|
|
|
$status = $check ? 2 : 1;
|
|
|
}else{ //更新
|
|
|
$status = $this->getFieldById($id, 'status');
|
|
|
//编辑草稿改变状态
|
|
|
if($status == 3){
|
|
|
$status = 1;
|
|
|
}
|
|
|
}
|
|
|
return $status;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取根节点id
|
|
|
* @return integer 数据id
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
protected function getRoot(){
|
|
|
$pid = I('post.pid');
|
|
|
if($pid == 0){
|
|
|
return 0;
|
|
|
}
|
|
|
$p_root = $this->getFieldById($pid, 'root');
|
|
|
return $p_root == 0 ? $pid : $p_root;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 创建时间不写则取当前时间
|
|
|
* @return int 时间戳
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
protected function getCreateTime(){
|
|
|
$create_time = I('post.create_time');
|
|
|
return $create_time?strtotime($create_time):NOW_TIME;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取扩展模型对象
|
|
|
* @param integer $model 模型编号
|
|
|
* @return object 模型对象
|
|
|
*/
|
|
|
private function logic($model){
|
|
|
$name = parse_name(get_document_model($model, 'name'), 1);
|
|
|
$class = is_file(MODULE_PATH . 'Logic/' . $name . 'Logic' . EXT) ? $name : 'Base';
|
|
|
$class = MODULE_NAME . '\\Logic\\' . $class . 'Logic';
|
|
|
return new $class($name);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查标识是否已存在(只需在同一根节点下不重复)
|
|
|
* @param string $name
|
|
|
* @return true无重复,false已存在
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
protected function checkName(){
|
|
|
$name = I('post.name');
|
|
|
$category_id = I('post.category_id', 0);
|
|
|
$id = I('post.id', 0);
|
|
|
|
|
|
$map = array('name' => $name, 'id' => array('neq', $id), 'status' => array('neq', -1));
|
|
|
|
|
|
$category = get_category($category_id);
|
|
|
if ($category['pid'] == 0) {
|
|
|
$map['category_id'] = $category_id;
|
|
|
} else {
|
|
|
$parent = get_parent_category($category['id']);
|
|
|
$root = array_shift($parent);
|
|
|
$map['category_id'] = array('in', D("Category")->getChildrenId($root['id']));
|
|
|
}
|
|
|
|
|
|
$res = $this->where($map)->getField('id');
|
|
|
if ($res) {
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 生成不重复的name标识
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
private function generateName(){
|
|
|
$str = 'abcdefghijklmnopqrstuvwxyz0123456789'; //源字符串
|
|
|
$min = 10;
|
|
|
$max = 39;
|
|
|
$name = false;
|
|
|
while (true){
|
|
|
$length = rand($min, $max); //生成的标识长度
|
|
|
$name = substr(str_shuffle(substr($str,0,26)), 0, 1); //第一个字母
|
|
|
$name .= substr(str_shuffle($str), 0, $length);
|
|
|
//检查是否已存在
|
|
|
$res = $this->getFieldByName($name, 'id');
|
|
|
if(!$res){
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return $name;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 生成推荐位的值
|
|
|
* @return number 推荐位
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
protected function getPosition(){
|
|
|
$position = I('post.position');
|
|
|
if(!is_array($position)){
|
|
|
return 0;
|
|
|
}else{
|
|
|
$pos = 0;
|
|
|
foreach ($position as $key=>$value){
|
|
|
$pos += $value; //将各个推荐位的值相加
|
|
|
}
|
|
|
return $pos;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 删除状态为-1的数据(包含扩展模型)
|
|
|
* @return true 删除成功, false 删除失败
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
public function remove(){
|
|
|
//查询假删除的基础数据
|
|
|
if ( is_administrator() ) {
|
|
|
$map = array('status'=>-1);
|
|
|
}else{
|
|
|
$cate_ids = AuthGroupModel::getAuthCategories(UID);
|
|
|
$map = array('status'=>-1,'category_id'=>array( 'IN',trim(implode(',',$cate_ids),',') ));
|
|
|
}
|
|
|
$base_list = $this->where($map)->field('id,model_id')->select();
|
|
|
//删除扩展模型数据
|
|
|
$base_ids = array_column($base_list,'id');
|
|
|
//孤儿数据
|
|
|
$orphan = get_stemma( $base_ids,$this, 'id,model_id');
|
|
|
|
|
|
$all_list = array_merge( $base_list,$orphan );
|
|
|
foreach ($all_list as $key=>$value){
|
|
|
$logic = $this->logic($value['model_id']);
|
|
|
$logic->delete($value['id']);
|
|
|
}
|
|
|
|
|
|
//删除基础数据
|
|
|
$ids = array_merge( $base_ids, (array)array_column($orphan,'id') );
|
|
|
if(!empty($ids)){
|
|
|
$res = $this->where( array( 'id'=>array( 'IN',trim(implode(',',$ids),',') ) ) )->delete();
|
|
|
}
|
|
|
|
|
|
return $res;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取链接id
|
|
|
* @return int 链接对应的id
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
protected function getLink(){
|
|
|
$link = I('post.link_id');
|
|
|
if(empty($link)){
|
|
|
return 0;
|
|
|
} else if(is_numeric($link)){
|
|
|
return $link;
|
|
|
}
|
|
|
$res = D('Url')->update(array('url'=>$link));
|
|
|
return $res['id'];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 保存为草稿
|
|
|
* @return array 完整的数据, false 保存出错
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
public function autoSave(){
|
|
|
$post = I('post.');
|
|
|
|
|
|
/* 检查文档类型是否符合要求 */
|
|
|
$res = $this->checkDocumentType( I('type',2), I('pid') );
|
|
|
if(!$res['status']){
|
|
|
$this->error = $res['info'];
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
//触发自动保存的字段
|
|
|
$save_list = array('name','title','description','position','link_id','cover_id','deadline','create_time','content');
|
|
|
foreach ($save_list as $value){
|
|
|
if(!empty($post[$value])){
|
|
|
$if_save = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(!$if_save){
|
|
|
$this->error = '您未填写任何内容';
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
//重置自动验证
|
|
|
$this->_validate = array(
|
|
|
array('name', '/^[a-zA-Z]\w{0,39}$/', '文档标识不合法', self::VALUE_VALIDATE, 'regex', self::MODEL_BOTH),
|
|
|
array('name', '', '标识已经存在', self::VALUE_VALIDATE, 'unique', self::MODEL_BOTH),
|
|
|
array('title', '1,80', '标题长度不能超过80个字符', self::VALUE_VALIDATE, 'length', self::MODEL_BOTH),
|
|
|
array('description', '1,140', '简介长度不能超过140个字符', self::VALUE_VALIDATE, 'length', self::MODEL_BOTH),
|
|
|
array('category_id', 'require', '分类不能为空', self::MUST_VALIDATE , 'regex', self::MODEL_BOTH),
|
|
|
array('category_id', 'check_category', '该分类不允许发布内容', self::EXISTS_VALIDATE , 'function', self::MODEL_UPDATE),
|
|
|
array('category_id,type', 'check_category', '内容类型不正确', self::MUST_VALIDATE, 'function', self::MODEL_INSERT),
|
|
|
array('model_id,pid,category_id', 'check_catgory_model', '该分类没有绑定当前模型', self::MUST_VALIDATE , 'function', self::MODEL_INSERT),
|
|
|
array('deadline', '/^\d{4,4}-\d{1,2}-\d{1,2}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/', '日期格式不合法,请使用"年-月-日 时:分"格式,全部为数字', self::VALUE_VALIDATE , 'regex', self::MODEL_BOTH),
|
|
|
array('create_time', '/^\d{4,4}-\d{1,2}-\d{1,2}(\s\d{1,2}:\d{1,2}(:\d{1,2})?)?$/', '日期格式不合法,请使用"年-月-日 时:分"格式,全部为数字', self::VALUE_VALIDATE , 'regex', self::MODEL_BOTH),
|
|
|
);
|
|
|
$this->_auto[] = array('status', '3', self::MODEL_BOTH);
|
|
|
|
|
|
if(!($data = $this->create())){
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/* 添加或新增基础内容 */
|
|
|
if(empty($data['id'])){ //新增数据
|
|
|
$id = $this->add(); //添加基础内容
|
|
|
if(!$id){
|
|
|
$this->error = '新增基础内容出错!';
|
|
|
return false;
|
|
|
}
|
|
|
$data['id'] = $id;
|
|
|
} else { //更新数据
|
|
|
$status = $this->save(); //更新基础内容
|
|
|
if(false === $status){
|
|
|
$this->error = '更新基础内容出错!';
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* 添加或新增扩展内容 */
|
|
|
$logic = $this->logic($data['model_id']);
|
|
|
if(!$logic->autoSave($id)){
|
|
|
if(isset($id)){ //新增失败,删除基础数据
|
|
|
$this->delete($id);
|
|
|
}
|
|
|
$this->error = $logic->getError();
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
//内容添加或更新完成
|
|
|
return $data;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查指定文档下面子文档的类型
|
|
|
* @param intger $type 子文档类型
|
|
|
* @param intger $pid 父文档类型
|
|
|
* @return array 键值:status=>是否允许(0,1),'info'=>提示信息
|
|
|
* @author huajie <banhuajie@163.com>
|
|
|
*/
|
|
|
public function checkDocumentType($type = null, $pid = null){
|
|
|
$res = array('status'=>1, 'info'=>'');
|
|
|
if(empty($type)){
|
|
|
return array('status'=>0, 'info'=>'文档类型不能为空');
|
|
|
}
|
|
|
if(empty($pid)){
|
|
|
return $res;
|
|
|
}
|
|
|
//查询父文档的类型
|
|
|
$ptype = is_numeric($pid) ? $this->getFieldById($pid, 'type') : $this->getFieldByName($pid, 'type');
|
|
|
//父文档为目录时
|
|
|
switch($ptype){
|
|
|
case 1: // 目录
|
|
|
case 2: // 主题
|
|
|
break;
|
|
|
case 3: // 段落
|
|
|
return array('status'=>0, 'info'=>'段落下面不允许再添加子内容');
|
|
|
default:
|
|
|
return array('status'=>0, 'info'=>'父文档类型不正确');
|
|
|
}
|
|
|
return $res;
|
|
|
}
|
|
|
|
|
|
} |