Skip to content

Instantly share code, notes, and snippets.

@summerblue
Created August 25, 2014 08:53
Show Gist options
  • Select an option

  • Save summerblue/607a4072486f6790fac5 to your computer and use it in GitHub Desktop.

Select an option

Save summerblue/607a4072486f6790fac5 to your computer and use it in GitHub Desktop.
<h2>用例 Use Case</h2>
<ul><li>会员可以对某个主题投票;</li>
<li>会员可以对某个回复进行投票;</li>
</ul>
<p>Laravel 的 ORM Eloquent 对这一类型的业务逻辑有很好的支持, 如下面几个例子</p>
<h4>一般 CMS 通用评论功能</h4>
<ul><li>用户可以对文章进行评论;</li>
<li>用户可以对用户进行评论;</li>
<li>用户可以对专题进行评论;</li>
</ul>
<h4>标签功能</h4>
<p>在某知名系统里面, 有 <code>post</code> 表和 <code>page</code> 表, 分别对应文章和页面.</p>
<ul><li>管理员可以给 <code>post</code> 打标签;</li>
<li>管理员可以对 <code>page</code> 打标签;</li>
</ul>
<p>这中类型的业务逻辑使用 Laravel 的 多态数据关系 (Polymorphic Relationship) 来解决那是最好不过了.</p>
<h2>开始代码</h2>
<h3>1. 添加 Route</h3>
<pre><code class="language-php"># ------------------ Votes ------------------------
Route::get('/topics/{id}/upvote', [
'as' =&gt; 'topics.upvote',
'uses' =&gt; 'TopicsController@upvote',
'before' =&gt; 'auth' // 需要登录用户才能访问.
]);
Route::get('/topics/{id}/downvote', [
'as' =&gt; 'topics.downvote',
'uses' =&gt; 'TopicsController@downvote',
'before' =&gt; 'auth'
]);
Route::get('/replies/{id}/vote', [
'as' =&gt; 'replies.vote',
'uses' =&gt; 'RepliesController@vote',
'before' =&gt; 'auth'
]);
</code></pre>
<p>我们使用了 <code>name route</code>, 这样在页面里面, 使用帮助函数</p>
<pre><code class="language-php">route('topics.upvote', $topic-&gt;id)
</code></pre>
<p>就可以生成类似以下的链接了.</p>
<pre><code>http://phphub.org/topics/20/upvote
</code></pre>
<h3>2. 添加页面入口</h3>
<p>此代码省略..., 下面是效果图</p>
<p><img src="http://ww1.sinaimg.cn/large/6d86d850gw1ejmov82c5sj20ku0biwfn.jpg" alt="" /></p>
<h3>3. 创建 Migration</h3>
<pre><code class="language-shell">php artisan generate:migration create_votes_table
</code></pre>
<p>上面命令会在 <code>app/database/migrations</code> 文件夹下生成类似于 <code>2014_08_20_130447_create_votes_table.php</code> 的文件.</p>
<p>在 <code>up</code> 方法里面填入以下</p>
<pre><code class="language-php">Schema::create('votes', function(Blueprint $table)
{
$table-&gt;increments('id');
$table-&gt;integer('user_id')-&gt;unsigned()-&gt;index();
$table-&gt;foreign('user_id')-&gt;references('id')-&gt;on('users')-&gt;onDelete('cascade');
$table-&gt;integer('votable_id')-&gt;index();
$table-&gt;string('votable_type')-&gt;index();
$table-&gt;string('is')-&gt;index();
$table-&gt;timestamps();
});
</code></pre>
<p>可读性很好的代码, 这里不解释.</p>
<h3>4. 创建 Model 文件</h3>
<pre><code class="language-shell">php artisan generate:model Vote
</code></pre>
<p>上面命令会在 <code>app/model/</code> 文件夹下生成 <code>Vote.php</code> 文件, 在里面添加以下几行方法</p>
<pre><code class="language-php">public function votable()
{
return $this-&gt;morphTo();
}
</code></pre>
<h3>5. 开始链接 Topic 和 Reply</h3>
<p>在 <code>app/model/Topic.php</code> 和 <code>app/model/Reply</code> 文件中加入相同的方法</p>
<pre><code class="language-php">public function votes()
{
return $this-&gt;morphMany('Vote', 'votable');
}
</code></pre>
<h3>6. 开始调用</h3>
<h4>Topic 话题</h4>
<p>以下是给 <code>Topic 话题</code> 投票的时候的调用, <code>TopicsController</code> 里面</p>
<pre><code class="language-php">public function upvote($id)
{
$topic = Topic::find($id);
$topic-&gt;votes()-&gt;create(['user_id' =&gt; Auth::user()-&gt;id, 'is' =&gt; 'upvote']);
return Redirect::back();
}
</code></pre>
<p>通过上面的 <code>create</code> 方法, 创建了一个 vote, 看下数据库里面的内容, 注意 <code>votable</code> 字段:</p>
<p><img src="http://ww4.sinaimg.cn/large/6d86d850gw1ejmq0sg3quj20on0fpwgi.jpg" alt="" /></p>
<h4>Reply 评论</h4>
<p>以下是给 <code>Reply 评论</code> 投票的时候的调用, <code>RepliesController</code> 里面</p>
<pre><code class="language-php">public function vote($id)
{
$reply = Reply::find($id);
$reply-&gt;votes()-&gt;create(['user_id' =&gt; Auth::user()-&gt;id, 'is' =&gt; 'upvote']);
return Redirect::back();
}
</code></pre>
<p>通过上面的 <code>create</code> 方法, 创建了一个 vote, 看下数据库里面的内容, 同样注意 <code>votable</code> 字段:</p>
<p><img src="http://ww4.sinaimg.cn/large/6d86d850gw1ejmq5wqpcpj20on0fpgnr.jpg" alt="" /></p>
<h2>总结</h2>
<p>介绍完了, 很神奇吧, 最少的代码, 兼顾可读性, 把一个复杂的逻辑轻轻松松的解决. 这就是 Laravel4. :+1:</p>
<blockquote>
<p>PHPHub 的 Vote 功能具体的代码请参照 <a href="https://github.com/summerblue/phphub">源码</a> .</p>
</blockquote>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment