Laravel问答7 Migration顶踩投票API

简介

当对某用户的回答做点赞或点差时,此时用户、回答两个实体之间存在多对多的关联关系,而用户、回答、投票三者组合必须是唯一的,即用户不能为回答投多票。而类似功能均可作为通用API来实现。

通用API应用场景

  • 当涉及到多表查询时需用通用API
  • 零碎功能点所需要的API

1.创建多对多关联关系

回答表和用户表之间隶属于多对多的关联关系,laravel中称这种中间表为轴心表。
(1)在模型中创建多对多的关联关系
app\Model\Answer.php

/*答案和用户之间隶属于多对多的关联关系*/
public function users()
{
    //默认中间表仅保存关联字段,新增字段需使用withPivot注明
    return $this
        ->belongsToMany('App\Model\User')
        ->withPivot('vote') //执行自定义新增字段(轴心)
        ->withTimestamps();//同时更新时间
}

app\Model\User.php

/*答案和用户之间隶属于多对多的关联关系*/
public function answers()
{
    //默认中间表仅保存关联字段,新增字段需使用withPivot注明
    return $this
        ->belongsToMany('App\Model\Answer')
        ->withPivot('vote') //执行自定义新增字段
        ->withTimestamps();//同时更新时间
}

(2)创建多对多中间表

php artisan make:migration create_table_answer_user --create=answer_user

注意:中间表表名不使用复数形式,必须使用单数。

(3)创建中间关联表结构

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTableAnswerUser extends Migration
{
    public function up()
    {
        Schema::create('answer_user', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            //自定义字段
            $table->unsignedInteger('user_id');//用户表主键
            $table->unsignedInteger('answer_id');//回答表主键
            $table->unsignedSmallInteger('vote');//票数
            //外键
            $table->foreign('user_id')->references('id')->on('user');
            $table->foreign('answer_id')->references('id')->on('answer');
            //唯一键设置
            $table->unique(['user_id','answer_id','vote']);
        });
    }
    public function down()
    {
        Schema::dropIfExists('answer_user');
    }
}

# 版本2
Schema::create('answer_user', function (Blueprint $table) {
    $table->increments('id');

    $table->unsignedInteger('user_id')->default('0')->comment('用户');
    $table->foreign('user_id')->references('id')->on('users');

    $table->unsignedInteger('answer_id')->default('0')->comment('回答');
    $table->foreign('answer_id')->references('id')->on('answers');
    
    $table->unsignedTinyInteger('vote')->default('0')->comment('投票:0踩1赞');

    $table->unique(['user_id','answer_id','vote']);//一个用户只能对一个问题投一次票(顶或踩)

    $table->timestamps();
});

(4)生成表结构

php artisan migrate:pretend
php artisan migrate
php artisan migrate:rollback

2. 为回答投票

(1)创建路由 routes\web.php

Route::any('/api/answer/vote',function(){
    return answerInstance()->vote();
});

(2)实现方法 app\Model\Answer.php

/*使用中间表为问题投票*/
public function vote()
{
    //检查用户是否登录
    if(!userInstance()->isLogin()){
        return ['err'=>1, 'msg'=>'请先登录'];
    }
    //判断必填参数
    if(!rq('id') || !rq('vote')){
        return ['err'=>1, 'msg'=>'参数错误'];
    }
    //检查回答是否存在
    $answer = $this->find(rq('id'));
    if(!$answer){
        return ['err'=>1, 'msg'=>'回答不存在'];
    }
    //检查当前用户是否在回答上重复投票,若中间表已存在数据则先存在后添加
    $answer->users()->newPivotStatement()
        ->where('user_id',session('user.id'))
        ->where('answer_id',rq('id'))
        ->delete();
    //向中间表添加
    $vote = rq('vote')<=1 ? 1 : 2;//1赞同 2反对
    $answer->users()->attach(session('user.id'),['vote'=>$vote]);
    return ['err'=>0];
}

# 版本2
/*API 用户投票*/
public function vote()
{
    //判断用户是否登录
    if(!user()->islogin()){
        return ['err'=>1, 'msg'=>'尚未登录'];
    }

    //判断回答编号和投票是否存在
    if(!rq('id')){
        return ['err'=>1, 'msg'=>'缺少回答编号'];
    }
    if(!Request::has('vote')){
        return ['err'=>1, 'msg'=>'缺少投票'];
    }

    //判断投票类型
    $vote = rq('vote') ? 1 : 0;//1顶0踩

    //判断问题是否存在
    $answer = $this->find(rq('id'));
    if(!$answer){
        return ['err'=>1, 'msg'=>'回答不存在'];
    }

    //判断用户在相同回答下是否已投票,注意 answer_user 中 answer_id+user_id+vote 必须唯一,即一个用户对一个问题只能投一票。
    //获取中间表
    $answer_user = $answer->user()->newPivotStatement();
    //删除投票记录
    $answer_user->where(['answer_id'=>rq('id'), 'user_id'=>session('user_id')])->delete();
    //添加投票
    $answer->user()->attach(session('user_id'), ['vote'=>$vote]);

    return ['err'=>0,'msg'=>'投票成功'];

}
基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统 基于laravel-vue--vux-element的视频投票系统
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值