PageRenderTime 25ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/var/Widget/Metas/Category/List.php

https://gitlab.com/wuhang2003/typecho
PHP | 402 lines | 193 code | 57 blank | 152 comment | 30 complexity | cb6a9f4dcd782a44dc2c940c723935e0 MD5 | raw file
  1. <?php
  2. if (!defined('__TYPECHO_ROOT_DIR__')) exit;
  3. /**
  4. * 分类输出
  5. *
  6. * @category typecho
  7. * @package Widget
  8. * @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
  9. * @license GNU General Public License 2.0
  10. * @version $Id$
  11. */
  12. /**
  13. * 分类输出组件
  14. *
  15. * @category typecho
  16. * @package Widget
  17. * @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
  18. * @license GNU General Public License 2.0
  19. */
  20. class Widget_Metas_Category_List extends Widget_Abstract_Metas
  21. {
  22. /**
  23. * 树状分类结构
  24. *
  25. * @var array
  26. * @access private
  27. */
  28. private $_treeViewCategories = array();
  29. /**
  30. * _categoryOptions
  31. *
  32. * @var mixed
  33. * @access private
  34. */
  35. private $_categoryOptions = NULL;
  36. /**
  37. * 顶层分类
  38. *
  39. * @var array
  40. * @access private
  41. */
  42. private $_top = array();
  43. /**
  44. * 所有分类哈希表
  45. *
  46. * @var array
  47. * @access private
  48. */
  49. private $_map = array();
  50. /**
  51. * 顺序流
  52. *
  53. * @var array
  54. * @access private
  55. */
  56. private $_orders = array();
  57. /**
  58. * 所有子节点列表
  59. *
  60. * @var array
  61. * @access private
  62. */
  63. private $_children = array();
  64. /**
  65. * 所有父节点列表
  66. *
  67. * @var array
  68. * @access private
  69. */
  70. private $_parents = array();
  71. /**
  72. * 构造函数,初始化组件
  73. *
  74. * @access public
  75. * @param mixed $request request对象
  76. * @param mixed $response response对象
  77. * @param mixed $params 参数列表
  78. */
  79. public function __construct($request, $response, $params = NULL)
  80. {
  81. parent::__construct($request, $response, $params);
  82. $this->parameter->setDefault('ignore=0&current=');
  83. $select = $this->select()->where('type = ?', 'category');
  84. if ($this->parameter->ignore) {
  85. $select->where('mid <> ?', $this->parameter->ignore);
  86. }
  87. $categories = $this->db->fetchAll($select->order('table.metas.order', Typecho_Db::SORT_ASC));
  88. foreach ($categories as $category) {
  89. $category['levels'] = 0;
  90. $this->_map[$category['mid']] = $category;
  91. }
  92. // 读取数据
  93. foreach ($this->_map as $mid => $category) {
  94. $parent = $category['parent'];
  95. if (0 != $parent && isset($this->_map[$parent])) {
  96. $this->_treeViewCategories[$parent][] = $mid;
  97. } else {
  98. $this->_top[] = $mid;
  99. }
  100. }
  101. // 预处理深度
  102. $this->levelWalkCallback($this->_top);
  103. $this->_map = array_map(array($this, 'filter'), $this->_map);
  104. }
  105. /**
  106. * 列出分类回调
  107. *
  108. * @access private
  109. */
  110. private function treeViewCategoriesCallback()
  111. {
  112. $categoryOptions = $this->_categoryOptions;
  113. if (function_exists('treeViewCategories')) {
  114. return treeViewCategories($this, $categoryOptions);
  115. }
  116. $classes = array();
  117. if ($categoryOptions->itemClass) {
  118. $classes[] = $categoryOptions->itemClass;
  119. }
  120. $classes[] = 'category-level-' . $this->levels;
  121. echo '<' . $categoryOptions->itemTag . ' class="'
  122. . implode(' ', $classes);
  123. if ($this->levels > 0) {
  124. echo ' category-child';
  125. $this->levelsAlt(' category-level-odd', ' category-level-even');
  126. } else {
  127. echo ' category-parent';
  128. }
  129. if ($this->mid == $this->parameter->current) {
  130. echo ' category-active';
  131. } else if (isset($this->_children[$this->mid]) && in_array($this->parameter->current, $this->_children[$this->mid])) {
  132. echo ' category-parent-active';
  133. }
  134. echo '"><a href="' . $this->permalink . '">' . $this->name . '</a>';
  135. if ($categoryOptions->showCount) {
  136. printf($categoryOptions->countTemplate, intval($this->count));
  137. }
  138. if ($categoryOptions->showFeed) {
  139. printf($categoryOptions->feedTemplate, $this->feedUrl);
  140. }
  141. if ($this->children) {
  142. $this->treeViewCategories();
  143. }
  144. echo '</' . $categoryOptions->itemTag . '>';
  145. }
  146. /**
  147. * 预处理分类迭代
  148. *
  149. * @param array $categories
  150. * @param array $parents
  151. * @access private
  152. */
  153. private function levelWalkCallback(array $categories, $parents = array())
  154. {
  155. foreach ($parents as $parent) {
  156. if (!isset($this->_children[$parent])) {
  157. $this->_children[$parent] = array();
  158. }
  159. $this->_children[$parent] = array_merge($this->_children[$parent], $categories);
  160. }
  161. foreach ($categories as $mid) {
  162. $this->_orders[] = $mid;
  163. $parent = $this->_map[$mid]['parent'];
  164. if (0 != $parent && isset($this->_map[$parent])) {
  165. $levels = $this->_map[$parent]['levels'] + 1;
  166. $this->_map[$mid]['levels'] = $levels;
  167. }
  168. $this->_parents[$mid] = $parents;
  169. if (!empty($this->_treeViewCategories[$mid])) {
  170. $new = $parents;
  171. $new[] = $mid;
  172. $this->levelWalkCallback($this->_treeViewCategories[$mid], $new);
  173. }
  174. }
  175. }
  176. /**
  177. * 子评论
  178. *
  179. * @access protected
  180. * @return array
  181. */
  182. protected function ___children()
  183. {
  184. return isset($this->_treeViewCategories[$this->mid]) ?
  185. $this->getCategories($this->_treeViewCategories[$this->mid]) : array();
  186. }
  187. /**
  188. * 执行函数
  189. *
  190. * @access public
  191. * @return void
  192. */
  193. public function execute()
  194. {
  195. $this->stack = $this->getCategories($this->_orders);
  196. }
  197. /**
  198. * treeViewCategories
  199. *
  200. * @access public
  201. * @return void
  202. */
  203. public function treeViewCategories()
  204. {
  205. $children = $this->children;
  206. if ($children) {
  207. //缓存变量便于还原
  208. $tmp = $this->row;
  209. $this->sequence ++;
  210. //在子评论之前输出
  211. echo '<' . $this->_categoryOptions->wrapTag . (empty($this->_categoryOptions->wrapClass)
  212. ? '' : ' class="' . $this->_categoryOptions->wrapClass . '"') . '>';
  213. foreach ($children as $child) {
  214. $this->row = $child;
  215. $this->treeViewCategoriesCallback();
  216. $this->row = $tmp;
  217. }
  218. //在子评论之后输出
  219. echo '</' . $this->_categoryOptions->wrapTag . '>';
  220. $this->sequence --;
  221. }
  222. }
  223. /**
  224. * treeViewCategories
  225. *
  226. * @param $categoryOptions 输出选项
  227. * @access public
  228. * @return void
  229. */
  230. public function listCategories($categoryOptions = NULL)
  231. {
  232. //初始化一些变量
  233. $this->_categoryOptions = Typecho_Config::factory($categoryOptions);
  234. $this->_categoryOptions->setDefault(array(
  235. 'wrapTag' => 'ul',
  236. 'wrapClass' => '',
  237. 'itemTag' => 'li',
  238. 'itemClass' => '',
  239. 'showCount' => false,
  240. 'showFeed' => false,
  241. 'countTemplate' => '(%d)',
  242. 'feedTemplate' => '<a href="%s">RSS</a>'
  243. ));
  244. // 插件插件接口
  245. $this->pluginHandle()->trigger($plugged)->listCategories($this->_categoryOptions, $this);
  246. if (!$plugged) {
  247. $this->stack = $this->getCategories($this->_top);
  248. if ($this->have()) {
  249. echo '<' . $this->_categoryOptions->wrapTag . (empty($this->_categoryOptions->wrapClass)
  250. ? '' : ' class="' . $this->_categoryOptions->wrapClass . '"') . '>';
  251. while ($this->next()) {
  252. $this->treeViewCategoriesCallback();
  253. }
  254. echo '</' . $this->_categoryOptions->wrapTag . '>';
  255. }
  256. $this->stack = $this->_map;
  257. }
  258. }
  259. /**
  260. * 根据深度余数输出
  261. *
  262. * @access public
  263. * @return void
  264. */
  265. public function levelsAlt()
  266. {
  267. $args = func_get_args();
  268. $num = func_num_args();
  269. $split = $this->levels % $num;
  270. echo $args[(0 == $split ? $num : $split) -1];
  271. }
  272. /**
  273. * 将每行的值压入堆栈
  274. *
  275. * @access public
  276. * @param array $value 每行的值
  277. * @return array
  278. */
  279. public function filter(array $value)
  280. {
  281. $value['directory'] = $this->getAllParents($value['mid']);
  282. $value['directory'][] = $value['slug'];
  283. $tmpCategoryTree = $value['directory'];
  284. $value['directory'] = implode('/', array_map('urlencode', $value['directory']));
  285. $value = parent::filter($value);
  286. $value['directory'] = $tmpCategoryTree;
  287. return $value;
  288. }
  289. /**
  290. * 获取某个分类下的所有子节点
  291. *
  292. * @param mixed $mid
  293. * @access public
  294. * @return array
  295. */
  296. public function getAllChildren($mid)
  297. {
  298. return isset($this->_children[$mid]) ? $this->_children[$mid] : array();
  299. }
  300. /**
  301. * 获取某个分类所有父级节点
  302. *
  303. * @param mixed $mid
  304. * @access public
  305. * @return array
  306. */
  307. public function getAllParents($mid)
  308. {
  309. $parents = array();
  310. if (isset($this->_parents[$mid])) {
  311. foreach ($this->_parents[$mid] as $parent) {
  312. $parents[] = $this->_map[$parent]['slug'];
  313. }
  314. }
  315. return $parents;
  316. }
  317. /**
  318. * 获取单个分类
  319. *
  320. * @param integer $mid
  321. * @access public
  322. * @return mixed
  323. */
  324. public function getCategory($mid)
  325. {
  326. return isset($this->_map[$mid]) ? $this->_map[$mid] : NULL;
  327. }
  328. /**
  329. * 获取多个分类
  330. *
  331. * @param mixed $mids
  332. * @access public
  333. * @return array
  334. */
  335. public function getCategories($mids)
  336. {
  337. $result = array();
  338. if (!empty($mids)) {
  339. foreach ($mids as $mid) {
  340. $result[] = $this->_map[$mid];
  341. }
  342. }
  343. return $result;
  344. }
  345. }