mirror of
https://git.beihong.wang/wangbeihong/blog-source.git
synced 2026-04-23 16:33:04 +08:00
515 lines
16 KiB
PHP
Executable File
515 lines
16 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Widget\Metas\Category;
|
|
|
|
use Typecho\Common;
|
|
use Typecho\Db\Exception;
|
|
use Typecho\Validate;
|
|
use Typecho\Widget\Helper\Form;
|
|
use Widget\Base\Metas;
|
|
use Widget\ActionInterface;
|
|
use Widget\Metas\EditTrait;
|
|
use Widget\Notice;
|
|
|
|
if (!defined('__TYPECHO_ROOT_DIR__')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* 编辑分类组件
|
|
*
|
|
* @category typecho
|
|
* @package Widget
|
|
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
|
|
* @license GNU General Public License 2.0
|
|
*/
|
|
class Edit extends Metas implements ActionInterface
|
|
{
|
|
use EditTrait;
|
|
|
|
/**
|
|
* 入口函数
|
|
* @throws \Exception
|
|
*/
|
|
public function execute()
|
|
{
|
|
/** 编辑以上权限 */
|
|
$this->user->pass('editor');
|
|
}
|
|
|
|
/**
|
|
* 判断分类是否存在
|
|
*
|
|
* @param integer $mid 分类主键
|
|
* @return boolean
|
|
* @throws Exception
|
|
*/
|
|
public function categoryExists(int $mid): bool
|
|
{
|
|
$category = $this->db->fetchRow($this->db->select()
|
|
->from('table.metas')
|
|
->where('type = ?', 'category')
|
|
->where('mid = ?', $mid)->limit(1));
|
|
|
|
return isset($category);
|
|
}
|
|
|
|
/**
|
|
* 判断分类名称是否存在
|
|
* fix #1843 将重复性判断限制在同一父分类下
|
|
*
|
|
* @param string $name 分类名称
|
|
* @return boolean
|
|
* @throws Exception
|
|
*/
|
|
public function nameExists(string $name): bool
|
|
{
|
|
$select = $this->db->select()
|
|
->from('table.metas')
|
|
->where('type = ?', 'category')
|
|
->where('name = ?', $name)
|
|
->limit(1);
|
|
|
|
if ($this->request->is('mid')) {
|
|
$select->where('mid <> ?', $this->request->get('mid'));
|
|
}
|
|
|
|
// 只在同一父分类下判断重复性
|
|
$select->where('parent = ?', $this->request->filter('int')->get('parent', 0));
|
|
|
|
$category = $this->db->fetchRow($select);
|
|
return !$category;
|
|
}
|
|
|
|
/**
|
|
* 判断分类名转换到缩略名后是否合法
|
|
*
|
|
* @param string $name 分类名
|
|
* @return boolean
|
|
* @throws Exception
|
|
*/
|
|
public function nameToSlug(string $name): bool
|
|
{
|
|
if (empty($this->request->slug)) {
|
|
$slug = Common::slugName($name);
|
|
if (empty($slug) || !$this->slugExists($name)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 判断分类缩略名是否存在
|
|
*
|
|
* @param string $slug 缩略名
|
|
* @return boolean
|
|
* @throws Exception
|
|
*/
|
|
public function slugExists(string $slug): bool
|
|
{
|
|
$select = $this->db->select()
|
|
->from('table.metas')
|
|
->where('type = ?', 'category')
|
|
->where('slug = ?', Common::slugName($slug))
|
|
->limit(1);
|
|
|
|
if ($this->request->is('mid')) {
|
|
$select->where('mid <> ?', $this->request->get('mid'));
|
|
}
|
|
|
|
$category = $this->db->fetchRow($select);
|
|
return !$category;
|
|
}
|
|
|
|
/**
|
|
* 增加分类
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
public function insertCategory()
|
|
{
|
|
if ($this->form('insert')->validate()) {
|
|
$this->response->goBack();
|
|
}
|
|
|
|
/** 取出数据 */
|
|
$category = $this->request->from('name', 'slug', 'description', 'parent');
|
|
|
|
$category['slug'] = Common::slugName(Common::strBy($category['slug'] ?? null, $category['name']));
|
|
$category['type'] = 'category';
|
|
$category['order'] = $this->getMaxOrder('category', $category['parent']) + 1;
|
|
|
|
/** 插入数据 */
|
|
$category['mid'] = $this->insert($category);
|
|
$this->push($category);
|
|
|
|
/** 设置高亮 */
|
|
Notice::alloc()->highlight($this->theId);
|
|
|
|
/** 提示信息 */
|
|
Notice::alloc()->set(
|
|
_t('分类 <a href="%s">%s</a> 已经被增加', $this->permalink, $this->name),
|
|
'success'
|
|
);
|
|
|
|
/** 转向原页 */
|
|
$this->response->redirect(Common::url('manage-categories.php'
|
|
. ($category['parent'] ? '?parent=' . $category['parent'] : ''), $this->options->adminUrl));
|
|
}
|
|
|
|
/**
|
|
* 生成表单
|
|
*
|
|
* @param string|null $action 表单动作
|
|
* @return Form
|
|
* @throws Exception
|
|
*/
|
|
public function form(?string $action = null): Form
|
|
{
|
|
/** 构建表格 */
|
|
$form = new Form($this->security->getIndex('/action/metas-category-edit'), Form::POST_METHOD);
|
|
|
|
/** 分类名称 */
|
|
$name = new Form\Element\Text('name', null, null, _t('分类名称') . ' *');
|
|
$form->addInput($name);
|
|
|
|
/** 分类缩略名 */
|
|
$slug = new Form\Element\Text(
|
|
'slug',
|
|
null,
|
|
null,
|
|
_t('分类缩略名'),
|
|
_t('分类缩略名用于创建友好的链接形式, 建议使用字母, 数字, 下划线和横杠.')
|
|
);
|
|
$form->addInput($slug);
|
|
|
|
/** 父级分类 */
|
|
$options = [0 => _t('不选择')];
|
|
$parents = Rows::allocWithAlias(
|
|
'options',
|
|
($this->request->is('mid') ? 'ignore=' . $this->request->get('mid') : '')
|
|
);
|
|
|
|
while ($parents->next()) {
|
|
$options[$parents->mid] = str_repeat(' ', $parents->levels) . $parents->name;
|
|
}
|
|
|
|
$parent = new Form\Element\Select(
|
|
'parent',
|
|
$options,
|
|
$this->request->get('parent'),
|
|
_t('父级分类'),
|
|
_t('此分类将归档在您选择的父级分类下.')
|
|
);
|
|
$form->addInput($parent);
|
|
|
|
/** 分类描述 */
|
|
$description = new Form\Element\Textarea(
|
|
'description',
|
|
null,
|
|
null,
|
|
_t('分类描述'),
|
|
_t('此文字用于描述分类, 在有的主题中它会被显示.')
|
|
);
|
|
$form->addInput($description);
|
|
|
|
/** 分类动作 */
|
|
$do = new Form\Element\Hidden('do');
|
|
$form->addInput($do);
|
|
|
|
/** 分类主键 */
|
|
$mid = new Form\Element\Hidden('mid');
|
|
$form->addInput($mid);
|
|
|
|
/** 提交按钮 */
|
|
$submit = new Form\Element\Submit();
|
|
$submit->input->setAttribute('class', 'btn primary');
|
|
$form->addItem($submit);
|
|
|
|
if (isset($this->request->mid) && 'insert' != $action) {
|
|
/** 更新模式 */
|
|
$meta = $this->db->fetchRow($this->select()
|
|
->where('mid = ?', $this->request->mid)
|
|
->where('type = ?', 'category')->limit(1));
|
|
|
|
if (!$meta) {
|
|
$this->response->redirect(Common::url('manage-categories.php', $this->options->adminUrl));
|
|
}
|
|
|
|
$name->value($meta['name']);
|
|
$slug->value($meta['slug']);
|
|
$parent->value($meta['parent']);
|
|
$description->value($meta['description']);
|
|
$do->value('update');
|
|
$mid->value($meta['mid']);
|
|
$submit->value(_t('编辑分类'));
|
|
$_action = 'update';
|
|
} else {
|
|
$do->value('insert');
|
|
$submit->value(_t('增加分类'));
|
|
$_action = 'insert';
|
|
}
|
|
|
|
if (empty($action)) {
|
|
$action = $_action;
|
|
}
|
|
|
|
/** 给表单增加规则 */
|
|
if ('insert' == $action || 'update' == $action) {
|
|
$name->addRule('required', _t('必须填写分类名称'));
|
|
$name->addRule([$this, 'nameExists'], _t('分类名称已经存在'));
|
|
$name->addRule([$this, 'nameToSlug'], _t('分类名称无法被转换为缩略名'));
|
|
$name->addRule('xssCheck', _t('请不要在分类名称中使用特殊字符'));
|
|
$slug->addRule([$this, 'slugExists'], _t('缩略名已经存在'));
|
|
$slug->addRule('xssCheck', _t('请不要在缩略名中使用特殊字符'));
|
|
}
|
|
|
|
if ('update' == $action) {
|
|
$mid->addRule('required', _t('分类主键不存在'));
|
|
$mid->addRule([$this, 'categoryExists'], _t('分类不存在'));
|
|
}
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* 更新分类
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
public function updateCategory()
|
|
{
|
|
if ($this->form('update')->validate()) {
|
|
$this->response->goBack();
|
|
}
|
|
|
|
/** 取出数据 */
|
|
$category = $this->request->from('name', 'slug', 'description', 'parent');
|
|
$category['mid'] = $this->request->get('mid');
|
|
$category['slug'] = Common::slugName(Common::strBy($category['slug'] ?? null, $category['name']));
|
|
$category['type'] = 'category';
|
|
$current = $this->db->fetchRow($this->select()->where('mid = ?', $category['mid']));
|
|
|
|
if ($current['parent'] != $category['parent']) {
|
|
$parent = $this->db->fetchRow($this->select()->where('mid = ?', $category['parent']));
|
|
|
|
if ($parent['mid'] == $category['mid']) {
|
|
$category['order'] = $parent['order'];
|
|
$this->update([
|
|
'parent' => $current['parent'],
|
|
'order' => $current['order']
|
|
], $this->db->sql()->where('mid = ?', $parent['mid']));
|
|
} else {
|
|
$category['order'] = $this->getMaxOrder('category', $category['parent']) + 1;
|
|
}
|
|
}
|
|
|
|
/** 更新数据 */
|
|
$this->update($category, $this->db->sql()->where('mid = ?', $this->request->filter('int')->get('mid')));
|
|
$this->push($category);
|
|
|
|
/** 设置高亮 */
|
|
Notice::alloc()->highlight($this->theId);
|
|
|
|
/** 提示信息 */
|
|
Notice::alloc()
|
|
->set(_t('分类 <a href="%s">%s</a> 已经被更新', $this->permalink, $this->name), 'success');
|
|
|
|
/** 转向原页 */
|
|
$this->response->redirect(Common::url('manage-categories.php'
|
|
. ($category['parent'] ? '?parent=' . $category['parent'] : ''), $this->options->adminUrl));
|
|
}
|
|
|
|
/**
|
|
* 删除分类
|
|
*
|
|
* @access public
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function deleteCategory()
|
|
{
|
|
$categories = $this->request->filter('int')->getArray('mid');
|
|
$deleteCount = 0;
|
|
|
|
foreach ($categories as $category) {
|
|
$parent = $this->db->fetchObject($this->select()->where('mid = ?', $category))->parent;
|
|
|
|
if ($this->delete($this->db->sql()->where('mid = ?', $category))) {
|
|
$this->db->query($this->db->delete('table.relationships')->where('mid = ?', $category));
|
|
$this->update(['parent' => $parent], $this->db->sql()->where('parent = ?', $category));
|
|
$deleteCount++;
|
|
}
|
|
}
|
|
|
|
/** 提示信息 */
|
|
Notice::alloc()
|
|
->set($deleteCount > 0 ? _t('分类已经删除') : _t('没有分类被删除'), $deleteCount > 0 ? 'success' : 'notice');
|
|
|
|
/** 转向原页 */
|
|
$this->response->goBack();
|
|
}
|
|
|
|
/**
|
|
* 合并分类
|
|
* @throws Exception
|
|
*/
|
|
public function mergeCategory()
|
|
{
|
|
/** 验证数据 */
|
|
$validator = new Validate();
|
|
$validator->addRule('merge', 'required', _t('分类主键不存在'));
|
|
$validator->addRule('merge', [$this, 'categoryExists'], _t('请选择需要合并的分类'));
|
|
|
|
if ($error = $validator->run($this->request->from('merge'))) {
|
|
Notice::alloc()->set($error, 'error');
|
|
$this->response->goBack();
|
|
}
|
|
|
|
$merge = $this->request->get('merge');
|
|
$categories = $this->request->filter('int')->getArray('mid');
|
|
|
|
if ($categories) {
|
|
$this->merge($merge, 'category', $categories);
|
|
|
|
/** 提示信息 */
|
|
Notice::alloc()->set(_t('分类已经合并'), 'success');
|
|
} else {
|
|
Notice::alloc()->set(_t('没有选择任何分类'));
|
|
}
|
|
|
|
/** 转向原页 */
|
|
$this->response->goBack();
|
|
}
|
|
|
|
/**
|
|
* 分类排序
|
|
* @throws Exception
|
|
*/
|
|
public function sortCategory()
|
|
{
|
|
$categories = $this->request->filter('int')->getArray('mid');
|
|
if ($categories) {
|
|
$this->sort($categories, 'category');
|
|
}
|
|
|
|
if (!$this->request->isAjax()) {
|
|
/** 转向原页 */
|
|
$this->response->redirect(Common::url('manage-categories.php', $this->options->adminUrl));
|
|
} else {
|
|
$this->response->throwJson(['success' => 1, 'message' => _t('分类排序已经完成')]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 刷新分类
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
public function refreshCategory()
|
|
{
|
|
$categories = $this->request->filter('int')->getArray('mid');
|
|
if ($categories) {
|
|
foreach ($categories as $category) {
|
|
$this->refreshCountByTypeAndStatus($category, 'post');
|
|
}
|
|
|
|
Notice::alloc()->set(_t('分类刷新已经完成'), 'success');
|
|
} else {
|
|
Notice::alloc()->set(_t('没有选择任何分类'));
|
|
}
|
|
|
|
/** 转向原页 */
|
|
$this->response->goBack();
|
|
}
|
|
|
|
/**
|
|
* 设置默认分类
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
public function defaultCategory()
|
|
{
|
|
/** 验证数据 */
|
|
$validator = new Validate();
|
|
$validator->addRule('mid', 'required', _t('分类主键不存在'));
|
|
$validator->addRule('mid', [$this, 'categoryExists'], _t('分类不存在'));
|
|
|
|
if ($error = $validator->run($this->request->from('mid'))) {
|
|
Notice::alloc()->set($error, 'error');
|
|
} else {
|
|
$this->db->query($this->db->update('table.options')
|
|
->rows(['value' => $this->request->get('mid')])
|
|
->where('name = ?', 'defaultCategory'));
|
|
|
|
$this->db->fetchRow($this->select()->where('mid = ?', $this->request->get('mid'))
|
|
->where('type = ?', 'category')->limit(1), [$this, 'push']);
|
|
|
|
/** 设置高亮 */
|
|
Notice::alloc()->highlight($this->theId);
|
|
|
|
/** 提示信息 */
|
|
Notice::alloc()->set(
|
|
_t('<a href="%s">%s</a> 已经被设为默认分类', $this->permalink, $this->name),
|
|
'success'
|
|
);
|
|
}
|
|
|
|
/** 转向原页 */
|
|
$this->response->redirect(Common::url('manage-categories.php', $this->options->adminUrl));
|
|
}
|
|
|
|
/**
|
|
* 获取菜单标题
|
|
*
|
|
* @return string|null
|
|
* @throws \Typecho\Widget\Exception|Exception
|
|
*/
|
|
public function getMenuTitle(): ?string
|
|
{
|
|
if ($this->request->is('mid')) {
|
|
$category = $this->db->fetchRow($this->select()
|
|
->where('type = ? AND mid = ?', 'category', $this->request->filter('int')->get('mid')));
|
|
|
|
if (!empty($category)) {
|
|
return _t('编辑分类 %s', $category['name']);
|
|
}
|
|
}
|
|
|
|
if ($this->request->is('parent')) {
|
|
$category = $this->db->fetchRow($this->select()
|
|
->where('type = ? AND mid = ?', 'category', $this->request->filter('int')->get('parent')));
|
|
|
|
if (!empty($category)) {
|
|
return _t('新增 %s 的子分类', $category['name']);
|
|
}
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
throw new \Typecho\Widget\Exception(_t('分类不存在'), 404);
|
|
}
|
|
|
|
/**
|
|
* 入口函数
|
|
*
|
|
* @access public
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function action()
|
|
{
|
|
$this->security->protect();
|
|
$this->on($this->request->is('do=insert'))->insertCategory();
|
|
$this->on($this->request->is('do=update'))->updateCategory();
|
|
$this->on($this->request->is('do=delete'))->deleteCategory();
|
|
$this->on($this->request->is('do=merge'))->mergeCategory();
|
|
$this->on($this->request->is('do=sort'))->sortCategory();
|
|
$this->on($this->request->is('do=refresh'))->refreshCategory();
|
|
$this->on($this->request->is('do=default'))->defaultCategory();
|
|
$this->response->redirect($this->options->adminUrl);
|
|
}
|
|
}
|