本书未发布

67. 新建话题

未匹配的标注

简介

本章我们将完成话题的 CURD (创建、编辑和详情页)开发,在本节里我们首先完成话题发布功能。

需求分解

创建话题的要求如下:

  • 只允许登录用户发布话题;
  • 新建表单里用户只能填写或选择话题的标题、分类和正文这三项内容;
  • reply_countview_countlast_reply_user_id 这三个属性属于程序维护,不需要给这三个属性赋值;
  • 在保存时自动把话题的创建用户ID( user_id ),设置成当前登录用户;
  • 在本节里,我们暂时让话题的摘要和标题相同,下一节再介绍摘要信息如何生成;
  • 话题发布成功后跳转到话题详情页。

对于「在保存时自动把话题的创建用户ID( user_id ),设置成当前登录用户」这一需求,我们使用数据模型的 数据完成 这一功能实现。数据完成 提供的 autoinstertupdate 三个属性,可以分别在写入、新增和更新的时候进行字段值的自动完成。因为在这里只要求创建保存时自动给 user_id 赋值,所以我们使用 insert 属性实现。

验证器

首先,我们创建话题验证器:

$ php think make:validate common/Topic

验证器代码如下:

application/common/validate/Topic.php

<?php

namespace app\common\validate;

use think\Validate;

class Topic extends Validate
{
    protected $rule = [
        'title' => 'require|length:3,50',
        'category_id' => 'require|egt:1',
        'body' => 'require|min:3',
    ];

    protected $message = [
        'title.require' => '标题不能为空',
        'title.length' => '标题长度必须在3-50个字符之间',
        'category_id.require' => '分类不能为空',
        'category_id.egt' => '分类不能为空',
        'body.require' => '正文不能为空',
        'body.min' => '正文至少包含3个字符',
    ];
}

数据模型

接下来,我们在 Topic 数据模型里定义创建保存方法:

'application/common/model/Topic.php'

<?php

namespace app\common\model;

use think\Model;
use app\common\validate\Topic as Validate;

class Topic extends Model
{
    // 新增实例记录时自动完成user_id字段赋值
    protected $insert = ['user_id'];
    .
    .
    .
    /**
     * user_id属性修改器
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2019-06-21
     */
    protected function setUserIdAttr(){
        // 当前登录用户ID
        $current_user = User::currentUser();
        if(empty($current_user)){
            return 0;
        }
        return $current_user->id;
    }

    /**
     * 创建记录
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2019-06-21
     * @param    array              $data 表单提交数据
     * @return   Topic                    [description]
     */
    public static function createItem($data)
    {
        $validate = new Validate;
        if(!$validate->batch(true)->check($data)){
            $e = new ValidateException('数据验证失败');
            $e->setData($validate->getError());
            throw $e;
        }

        try{
            $topic = new self;
            $topic->allowField(true)->save($data);
        }catch (\Exception $e){
            throw new \Exception('创建话题失败');
        }

        return $topic;
    }
}

控制器

在上一章我们使用命令行已经生成了话题控制器,所以我们现在打开已生成的控制器在里面完成话题创建方法代码。

另外,因为需求「只允许登录用户发布话题」,所以我们需要在控制器里使用 auth 中间件限制创建权限,和之前控制器一样在这里我们使用 except 属性注册中间件。

<?php

namespace app\index\controller;

use think\Request;
use app\common\model\Topic as TopicModel;
use app\common\model\Category as CategoryModel;
use app\common\exception\ValidateException;

class Topic extends Base
{
    protected $middleware = [
        'auth' => ['except' => ['index']],
    ];

    .
    .
    .
    public function create()
    {
        $categories = CategoryModel::all();
        $this->assign('categories', $categories);
        $this->assign('topic', []);
        return $this->fetch('form');
    }

    public function save(Request $request)
    {
        if(!$request->isAjax()){
            $this->redirect('[topic.create]');
        }

        try{
            $data = $request->post();
            $topic = TopicModel::createItem($data);
        }catch (ValidateException $e){
            $this->error($e->getMessage(), '', ['errors' => $e->getData()]);
        }catch (\Exception $e){
            $this->error($e->getMessage());
        }

        $this->success('创建成功', url('[topic.read]', ['id' => $topic->id]));
    }
    .
    .
    .
}

因为用户发帖时我们让用户选择话题分类,所以我们在 create() 方法里将所有的分类读取赋值给变量 $categories,并传入视图页面中。

路由

在路由文件里添加创建话题路由配置:

route/route.php

<?php
.
.
.
// 话题管理
Route::get('topic/create', 'topic/create')->name('topic.create');
Route::post('topic', 'topic/save')->name('topic.save');
Route::get('topic', 'topic/index')->name('topic.index');
Route::get('category/<id>', 'category/read')->name('category.read');

注意,路由 topic.savetopic.save 一定要定义在 topic.index 前面。

视图模板

  1. 我们在顶部导航栏新增发帖入口:

application/index/view/layout/_header.html

.
.
.
<!-- Authentication Links -->
{empty name="current_user"}
  <li class="nav-item"><a class="nav-link" href="{:url('[page.login]')}">登录</a></li>
  <li class="nav-item"><a class="nav-link" href="{:url('[page.signup]')}">注册</a></li>
{else/}
  <li class="nav-item">
    <a class="nav-link mt-1 mr-3 font-weight-bold" href="{:url('[topic.create]')}">
      <i class="fa fa-plus"></i>
    </a>
  </li>
  <li class="nav-item dropdown">
.
.
.
  1. 我们在右边导航栏新增发帖入口:

application/index/view/topic/_sidebar.html

<div class="card ">
    <div class="card-body">
        <a href="{:url('[topic.create]')}" class="btn btn-success btn-block" aria-label="Left Align">
            <i class="fas fa-pencil-alt mr-2"></i>  新建话题
        </a>
    </div>
</div>

刷新页面:
【截图】
现在我们可以很方便的通过顶部导航栏进入话题发布页面。

  1. 我们完成话题创建表单页面:

application/index/view/topic/form.html

{extend name="layout/main" /}
{block name="content"}
<div class="container">
    <div class="col-md-10 col-md-offset-1">
        <div class="panel panel-default">

            <div class="panel-heading">
                <h1>
                    <i class="glyphicon glyphicon-edit"></i>
                    新建话题
                </h1>
            </div>

            <div class="panel-body">
                <form id='model-form' action="{:url('[topic.save]')}" method="POST" accept-charset="UTF-8">
                    <div class="form-group">
                        <input class="form-control" type="text" name="title" id="title-field" value="" placeholder="请填写标题" required/>
                    </div>
                    <div class="form-group">
                        <select class="form-control" name="category_id" required>
                            <option value="" hidden disabled selected>请选择分类</option>
                            {volist name='categories' id='category'}
                                <option value="{$category->id}">{$category->name}</option>
                            {/volist}
                        </select>
                    </div>
                    <div class="form-group">
                        <textarea name="body" id="body-field" class="form-control" rows="3"></textarea>
                    </div>
                    <div class="well well-sm">
                        <button type="submit" class="btn btn-primary">保存</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
{/block}
{block name="scripts"}
<script src="/static/assets/plugins/jquery-validate/jquery.validate.min.js"></script>
<script src="/static/assets/plugins/jquery-validate/bootstrap.validate.js"></script>
<script type="text/javascript">
    jQuery(function($){
        validAndSubmitForm(
            "form#model-form",
            {
                "title":{
                    required: true,
                    rangelength: [3, 50]
                }, "category_id":{
                    required: true,
                    min: 1
                }, "body":{
                    required: true,
                    minlength: 3
                }
            }, {
                "title":{
                    required: "标题不能为空",
                    rangelength: "标题长度必须在3-50个字符之间"
                }, "category_id":{
                    required: "分类不能为空",
                    min: "分类不能为空"
                }, "body":{
                    required: "正文不能为空",
                    minlength: "正文至少包含3个字符"
                }
            }
        );
    });
</script>
{/block}

效果展示

Git 版本控制

下面把代码纳入到版本管理:

$ git add -A
$ git commit -m "用户可以创建话题"

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~