📄 正在查看:twcms/model/category_model.class.php
大小:10,646 字节 · 修改:2014-01-23 19:35:16 · 行数:382
1<?php
2/**
3 * (C)2012-2014 twcms.com TongWang Inc.
4 * Author: wuzhaohuan <kongphp@gmail.com>
5 */
6
7defined('TWCMS_PATH') or exit;
8
9class category extends model {
10 private $data = array(); // 防止重复查询
11
12 function __construct() {
13 $this->table = 'category'; // 表名
14 $this->pri = array('cid'); // 主键
15 $this->maxid = 'cid'; // 自增字段
16 }
17
18 // 暂时用些方法解决获取 cfg 值
19 function __get($var) {
20 if($var == 'cfg') {
21 return $this->cfg = $this->runtime->xget();
22 }else{
23 return parent::__get($var);
24 }
25 }
26
27 // 检查基本参数是否填写
28 public function check_base(&$post) {
29 if(empty($post['mid'])) {
30 $name = 'mid';
31 $msg = '请选择分类模型';
32 }elseif(!isset($post['type'])) {
33 $name = 'type';
34 $msg = '请选择分类属性';
35 }elseif(!isset($post['upid'])) {
36 $name = 'upid';
37 $msg = '请选择所属频道';
38 }elseif(strlen($post['name']) < 1) {
39 $name = 'name';
40 $msg = '请填写分类名称';
41 }elseif(strlen($post['alias']) < 1) {
42 $name = 'alias';
43 $msg = '请填写分类别名';
44 }elseif(strlen($post['alias']) > 50) {
45 $name = 'alias';
46 $msg = '分类别名不能超过50个字符';
47 }elseif(empty($post['cate_tpl'])) {
48 $name = 'cate_tpl';
49 $msg = '请填写分类页模板';
50 }elseif($post['mid'] > 1 && empty($post['show_tpl'])) {
51 $name = 'show_tpl';
52 $msg = '请填写内容页模板';
53 }
54 return empty($msg) ? FALSE : array('name' => $name, 'msg' => $msg);
55 }
56
57 // 检查别名是否被使用
58 public function check_alias($alias) {
59 $msg = $this->only_alias->check_alias($alias);
60 return empty($msg) ? FALSE : array('name' => 'alias', 'msg' => $msg);
61 }
62
63 // 检查是否符合修改条件
64 public function check_is_edit($post, $data) {
65 if($post['cid'] == $post['upid']) {
66 $name = 'upid';
67 $msg = '所属频道不能修改为自己'; // 暂时不考虑 upid 不能为自己的下级分类或非频道分类 (前端已经限制)
68 }elseif($data['count'] > 0 && $post['mid'] != $data['mid']) {
69 $name = 'mid';
70 $msg = '分类中有内容,不允许修改分类模型,请先清空分类内容';
71 }elseif($data['count'] > 0 && $post['type'] != $data['type']) {
72 $name = 'type';
73 $msg = '分类中有内容,不允许修改分类属性,请先清空分类内容';
74 }elseif($data['type'] == 1 && $post['mid'] != $data['mid'] && $this->check_is_son($data['cid'])) {
75 $name = 'mid';
76 $msg = '分类有下级分类,不允许修改分类模型';
77 }elseif($data['type'] == 1 && $post['type'] != $data['type'] && $this->check_is_son($data['cid'])) {
78 $name = 'type';
79 $msg = '分类有下级分类,不允许修改分类类型';
80 }
81 return empty($msg) ? FALSE : array('name' => $name, 'msg' => $msg);
82 }
83
84 // 检查是否符合删除条件
85 public function check_is_del($data) {
86 if($data['type'] == 1 && $this->check_is_son($data['cid'])) {
87 return '分类有下级分类,请先删除下级分类';
88 }elseif($data['count'] > 0) {
89 return '分类中有内容,请先删除内容';
90 }
91 return FALSE;
92 }
93
94 // 检查是否有下级分类
95 public function check_is_son($upid) {
96 return $this->find_fetch_key(array('upid' => $upid), array(), 0, 1) ? TRUE : FALSE;
97 }
98
99 // 从数据库获取分类
100 public function get_category_db() {
101 if(isset($this->data['category_db'])) {
102 return $this->data['category_db'];
103 }
104
105 // hook category_model_get_category_db_before.php
106
107 $arr = array();
108 $tmp = $this->find_fetch(array(), array('orderby'=>1));
109 foreach($tmp as $v) {
110 $arr[$v['cid']] = $v;
111 }
112
113 // hook category_model_get_category_db_after.php
114
115 return $this->data['category_db'] = $arr;
116 }
117
118 // 获取分类 (树状结构)
119 public function get_category_tree() {
120 if(isset($this->data['category_tree'])) {
121 return $this->data['category_tree'];
122 }
123
124 $this->data['category_tree'] = array();
125 $tmp = $this->get_category_db();
126
127 // 格式化为树状结构 (会舍弃不合格的结构)
128 foreach($tmp as $v) {
129 $tmp[$v['upid']]['son'][$v['cid']] = &$tmp[$v['cid']];
130 }
131 $this->data['category_tree'] = isset($tmp['0']['son']) ? $tmp['0']['son'] : array();
132
133 // 格式化为树状结构 (不会舍弃不合格的结构)
134 // foreach($tmp as $v) {
135 // if(isset($tmp[$v['upid']])) $tmp[$v['upid']]['son'][] = &$tmp[$v['cid']];
136 // else $this->data['category_tree'][] = &$tmp[$v['cid']];
137 // }
138
139 return $this->data['category_tree'];
140 }
141
142 // 获取分类 (二维数组)
143 public function get_category() {
144 if(isset($this->data['category_array'])) {
145 return $this->data['category_array'];
146 }
147
148 $arr = $this->get_category_tree();
149 return $this->data['category_array'] = $this->to_array($arr);
150 }
151
152 // 递归转换为二维数组
153 public function to_array($data, $pre = 1) {
154 static $arr = array();
155
156 foreach($data as $k => $v) {
157 $v['pre'] = $pre;
158 if(isset($v['son'])) {
159 $arr[$v['mid']][] = $v;
160 self::to_array($v['son'], $pre+1);
161 }else{
162 $arr[$v['mid']][] = $v;
163 }
164 }
165
166 return $arr;
167 }
168
169 // 获取模型下级所有列表分类的cid
170 public function get_cids_by_mid($mid) {
171 $k = 'cate_by_mid_'.$mid;
172 if(isset($this->data[$k])) return $this->data[$k];
173
174 $arr = $this->runtime->xget($k);
175 if(empty($arr)) {
176 $arr = $this->get_cids_by_upid(0, $mid);
177 $this->runtime->set($k, $arr);
178 }
179 $this->data[$k] = $arr;
180 return $arr;
181 }
182
183 // 获取频道分类下级列表分类的cid
184 public function get_cids_by_upid($upid, $mid) {
185 $arr = array();
186 $tmp = $this->get_category_db();
187 if($upid != 0 && !isset($tmp[$upid])) return FALSE;
188
189 foreach($tmp as $k => $v) {
190 if($v['mid'] == $mid) {
191 $tmp[$v['upid']]['son'][$v['cid']] = &$tmp[$v['cid']];
192 }else{
193 unset($tmp[$k]);
194 }
195 }
196
197 if(isset($tmp[$upid]['son'])) {
198 foreach($tmp[$upid]['son'] as $k => $v) {
199 if($v['type'] == 1) {
200 $arr[$k] = isset($v['son']) ? self::recursion_cid($v['son']) : array();
201 }elseif($v['type'] == 0) {
202 $arr[$k] = 1;
203 }
204 }
205 }
206
207 return $arr;
208 }
209
210 // 递归获取下级分类全部 cid
211 public function recursion_cid(&$data) {
212 $arr = array();
213 foreach($data as $k => $v) {
214 if(isset($v['son'])) {
215 $arr2 = self::recursion_cid($v['son']);
216 $arr = array_merge($arr, $arr2);
217 }else{
218 if($v['type'] == 0) {
219 $arr[] = intval($v['cid']);
220 }
221 }
222 }
223 return $arr;
224 }
225
226 // 获取分类下拉列表HTML (内容发布时使用)
227 public function get_cidhtml_by_mid($_mid, $cid, $tips = '选择分类') {
228 $category_arr = $this->get_category();
229
230 $s = '<select name="cid" id="cid">';
231 if(empty($category_arr)) {
232 $s .= '<option value="0">没有分类</option>';
233 }else{
234 $s .= '<option value="0">'.$tips.'</option>';
235 foreach($category_arr as $mid => $arr) {
236 if($mid != $_mid) continue;
237
238 foreach($arr as $v) {
239 $disabled = $v['type'] == 1 ? ' disabled="disabled"' : '';
240 $s .= '<option value="'.$v['cid'].'"'.($v['type'] == 0 && $v['cid'] == $cid ? ' selected="selected"' : '').$disabled.'>';
241 $s .= str_repeat(" ", $v['pre']-1);
242 $s .= '|─'.$v['name'].($v['type'] == 1 ? '[频道]' : '').'</option>';
243 }
244 }
245 }
246 $s .= '</select>';
247 return $s;
248 }
249
250 // 获取上级分类的 HTML 代码 (只显示频道分类)
251 public function get_category_upid($mid, $upid = 0, $noid = 0) {
252 $category_arr = $this->get_category();
253
254 $s = '<option value="0">无</option>';
255 if(isset($category_arr[$mid])) {
256 foreach($category_arr[$mid] as $v) {
257 // 不显示列表的分类
258 if($mid> 1 && $v['type'] == 0) continue;
259
260 // 当 $noid 有值时,排除等于它和它的下级分类
261 if($noid) {
262 if(isset($pre)) {
263 if($v['pre'] > $pre) continue;
264 else unset($pre);
265 }
266 if($v['cid'] == $noid) {
267 $pre = $v['pre'];
268 continue;
269 }
270 }
271
272 $s .= '<option value="'.$v['cid'].'"'.($v['cid'] == $upid ? ' selected="selected"' : '').'>';
273 $s .= str_repeat(" ", $v['pre']-1);
274 $s .= '|─'.$v['name'].'</option>';
275 }
276 }
277
278 return $s;
279 }
280
281 // 获取指定分类的 mid (如果 cid 为空,则读第一个分类的 mid)
282 public function get_mid_by_cid($cid) {
283 if($cid) {
284 $arr = $this->read($cid);
285 }else{
286 $arr = $this->get_category();
287 if(empty($arr)) return 2;
288
289 $arr = current($arr);
290 $arr = current($arr);
291 }
292 return $arr['mid'];
293 }
294
295 // 获取分类当前位置
296 public function get_place($cid) {
297 $p = array();
298 $tmp = $this->get_category_db();
299
300 while(isset($tmp[$cid]) && $v = &$tmp[$cid]) {
301 array_unshift($p, array(
302 'cid'=> $v['cid'],
303 'name'=> $v['name'],
304 'url'=> $this->category_url($v['cid'], $v['alias'])
305 ));
306 $cid = $v['upid'];
307 }
308
309 return $p;
310 }
311
312 // 获取分类缓存合并数组
313 public function get_cache($cid) {
314 $k = 'cate_'.$cid;
315 if(isset($this->data[$k])) return $this->data[$k];
316
317 $arr = $this->runtime->xget($k);
318 if(empty($arr)) {
319 $arr = $this->update_cache($cid);
320 }
321 $this->data[$k] = $arr;
322 return $arr;
323 }
324
325 // 更新分类缓存合并数组
326 public function update_cache($cid) {
327 $k = 'cate_'.$cid;
328 $arr = $this->read($cid);
329 if(empty($arr)) return FALSE;
330
331 $arr['place'] = $this->get_place($cid); // 分类当前位置
332 $arr['topcid'] = $arr['place'][0]['cid']; // 顶级分类CID
333 $arr['table'] = $this->cfg['table_arr'][$arr['mid']]; // 分类模型表名
334
335 // 如果为频道,获取频道分类下级CID
336 if($arr['type'] == 1) {
337 $arr['son_list'] = $this->get_cids_by_upid($cid, $arr['mid']);
338 $arr['son_cids'] = array();
339 if(!empty($arr['son_list'])) {
340 foreach($arr['son_list'] as $c => $v) {
341 if(is_array($v)) {
342 $v && $arr['son_cids'] = array_merge($arr['son_cids'], $v);
343 }else{
344 $arr['son_cids'][] = $c;
345 }
346 }
347 }
348 }
349
350 // hook category_model_update_cache_after.php
351
352 $this->runtime->set($k, $arr);
353 return $arr;
354 }
355
356 // 删除所有分类缓存 (最多读取2000条,如果缓存太大,需要手工清除缓存)
357 public function delete_cache() {
358 $key_arr = $this->runtime->find_fetch_key(array(), array(), 0, 2000);
359 foreach ($key_arr as $v) {
360 if(substr($v, 10, 5) == 'cate_') {
361 $this->runtime->delete(substr($v, 10));
362 }
363 }
364 return TRUE;
365 }
366
367 // 分类链接格式化
368 public function category_url(&$cid, &$alias, $page = FALSE) {
369 // hook category_model_category_url_before.php
370
371 if(empty($_ENV['_config']['twcms_parseurl'])) {
372 return $this->cfg['webdir'].'index.php?cate--cid-'.$cid.($page ? '-page-{page}' : '').$_ENV['_config']['url_suffix'];
373 }else{
374 if($page) {
375 return $this->cfg['webdir'].$alias.$this->cfg['link_cate_page_pre'].'{page}'.$this->cfg['link_cate_page_end'];
376 }else{
377 return $this->cfg['webdir'].$alias.$this->cfg['link_cate_end'];
378 }
379 }
380 }
381}
382