源码分析 - PHPHub 的 Vote 功能与 Laravel 多态数据关系 (Polymorphic Relationship)
23

用例 Use Case

  • 会员可以对某个主题投票;
  • 会员可以对某个回复进行投票;

Laravel 的 ORM Eloquent 对这一类型的业务逻辑有很好的支持, 如下面几个例子

一般 CMS 通用评论功能

  • 用户可以对文章进行评论;
  • 用户可以对用户进行评论;
  • 用户可以对专题进行评论;

标签功能

在某知名系统里面, 有 post 表和 page 表, 分别对应文章和页面.

  • 管理员可以给 post 打标签;
  • 管理员可以对 page 打标签;

这中类型的业务逻辑使用 Laravel 的 多态数据关系 (Polymorphic Relationship) 来解决那是最好不过了.

开始代码

1. 添加 Route

# ------------------ Votes ------------------------

Route::get('/topics/{id}/upvote', [
    'as' => 'topics.upvote',
    'uses' => 'TopicsController@upvote',
    'before' => 'auth' // 需要登录用户才能访问.
]);

Route::get('/topics/{id}/downvote', [
    'as' => 'topics.downvote',
    'uses' => 'TopicsController@downvote',
    'before' => 'auth'
]);

Route::get('/replies/{id}/vote', [
    'as' => 'replies.vote',
    'uses' => 'RepliesController@vote',
    'before' => 'auth'
]);

我们使用了 name route, 这样在页面里面, 使用帮助函数

route('topics.upvote', $topic->id)

就可以生成类似以下的链接了.

http://phphub.org/topics/20/upvote

2. 添加页面入口

此代码省略..., 下面是效果图

3. 创建 Migration

php artisan generate:migration create_votes_table

上面命令会在 app/database/migrations 文件夹下生成类似于 2014_08_20_130447_create_votes_table.php 的文件.

up 方法里面填入以下

Schema::create('votes', function(Blueprint $table)
{
    $table->increments('id');
    $table->integer('user_id')->unsigned()->index();
    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

    $table->integer('votable_id')->index();
    $table->string('votable_type')->index();
    $table->enum('is', ['upvote', 'downvote']);

    $table->timestamps();
});

可读性很好的代码, 这里不解释.

4. 创建 Model 文件

php artisan generate:model Vote

上面命令会在 app/model/ 文件夹下生成 Vote.php 文件, 在里面添加以下几行方法

public function votable()
{
   return $this->morphTo();
}

5. 开始链接 Topic 和 Reply

app/model/Topic.phpapp/model/Reply 文件中加入相同的方法

public function votes()
{
    return $this->morphMany('Vote', 'votable');
}

6. 开始调用

Topic 话题

以下是给 Topic 话题 投票的时候的调用, TopicsController 里面

public function upvote($id)
{
    $topic = Topic::find($id);
    $topic->votes()->create(['user_id' => Auth::user()->id, 'is' => 'upvote']);
    return Redirect::back();
}

通过上面的 create 方法, 创建了一个 vote, 看下数据库里面的内容, 注意 votable 字段:

Reply 评论

以下是给 Reply 评论 投票的时候的调用, RepliesController 里面

public function vote($id)
{
   $reply = Reply::find($id);
   $reply->votes()->create(['user_id' => Auth::user()->id, 'is' => 'upvote']);
   return Redirect::back();
}

通过上面的 create 方法, 创建了一个 vote, 看下数据库里面的内容, 同样注意 votable 字段:

总结

介绍完了, 很神奇吧, 最少的代码, 兼顾可读性, 把一个复杂的逻辑轻轻松松的解决. 这就是 Laravel4. :+1:

PHPHub 的 Vote 功能具体的代码请参照 源码 .

本帖已被设为精华帖!
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 17
Summer

@lovecn 今天修改.

4年前

更新删除怎么做

1年前
杨子鳄鱼

@Summer 多态的删除怎么做, 如点赞和取消点赞

9个月前

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,使用方法请见 Emoji 自动补全来咯,可用的 Emoji 请见 :metal: :point_right: Emoji 列表 :star: :sparkles:
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
  • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!