weixin_39838231
weixin_39838231
2021-01-09 10:35

2017 版 Laravel 系列入门教程(五)【最适合中国人的 Laravel 教程】

本文是本系列教程的完结篇,我们将一起给 Article 加入评论功能,让游客在前台页面可以查看、提交、回复评论,并完成后台评论管理功能,可以删除、编辑评论。Article 和评论将使用 Laravel Eloquent 提供的“一对多关系”功能大大简化模型间关系的复杂度。最终,我们将得到一个个人博客系统的雏形,并布置一个大作业,供大家实战练习。

本篇文章中我将会使用一些 Laravel 的高级功能,这些高级功能对新手理解系统是不利的,但熟手使用这些功能可以大幅提升开发效率。

回顾 Eloquent

前面我们已经说过,Laravel Eloquent ORM 是 Laravel 中最强大的部分,也是 Laravel 能如此流行最重要的原因。中文文档在:https://d.laravel-china.org/docs/5.5/eloquent

learnlaravel5/app/Article.php 就是一个最简单的 Eloquent Model 类:

 php
<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    //
}
omment 的 Model 类,并顺便创建附带的 migration,在 learnlaravel5 目录下运行命令:

若想进一步了解 Eloquent 推荐阅读系列文章:深入理解 Laravel Eloquent

构建评论系统

基础规划

我们需要新建一个表专门用来存放每一条评论,每一条评论都属于某一篇文章。评论之间的层级关系比较复杂,本文为入门教程,主要是为了带领大家体验模型间关系,就不再做过多的规划了,将“回复别人的评论”暂定为简单的在评论内容前面增加 这样的字符串。

建立 Model 类和数据表

创建名为 Comment 的 Model 类,并顺便创建附带的 migration,在 learnlaravel5 目录下运行命令:

 bash
php artisan make:model Comment -m
        $table-> $table->
<p>这样一次性建立了 Comment 类和 <code>learnlaravel5/database/migrations/2017_11_11_151823_create_comments_table.php 两个文件。填充该文件的 up 方法,给 comments 表增加字段:
 php
public function up()
{
    Schema::create('comments', function (Blueprint $table) {
        $table->increments('id');
        $table->string('nickname');
        $table->string('email')->nullable();
        $table->string('website')->nullable();
        $table->text('content')->nullable();
        $table->integer('article_id');
        $table->timestamps();
    });
}

在 Article 模型中增加一对多关系的函数:

<pre>cle 模型中增加一对多关系的函数:

<pre>
<p>之后运行命令:</p>
<pre><code> bash
php artisan migrate
namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    public function hasManyComments()
    {
        return $this->ce App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    public function hasManyComments()
    {
        return $this->
<p>去数据库里瞧瞧,comments 表已经躺在那儿啦。</p>
<h3>建立“一对多关系”</h3>
<p>在 Article 模型中增加一对多关系的函数:</p>
<pre><code> php
<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    public function hasManyComments()
    {
        return $this->hasMany('App\Comment', 'article_id', 'id');
    }
}
#### 创建前台的 ArticleController 类

运行命令:

<pre>前台的 ArticleController 类

运行命令:

<pre>
<p>搞定啦!Eloquent 中模型间关系就是这么简单!</p>
<p>模型间关系中文文档:http://laravel-china.org/docs/5.1/eloquent-relationships
扩展阅读:<a href="https://lvwenhan.com/laravel/423.html">深入理解 Laravel Eloquent(三)——模型间关系(关联)</a></p>
<h3>构建前台 UI</h3>
<p>让我们修改前台的视图文件,想办法把评论功能加进去。</p>
<h4>创建前台的 ArticleController 类</h4>
<p>运行命令:</p>
<pre><code> bash
php artisan make:controller ArticleController

<pre>code>
<p>增加路由:</p>
<pre><code> php
Route::get('article/{id}', 'ArticleController');

此处的 {id} 指代任意字符串,在我们的规划中,此字段为文章 ID,为数字,但是本行路由却会尝试匹配所有请求,所以当你遇到了奇怪的路由调用的方法跟你想象的不一样时,记得检查路由顺序。路由匹配方式为前置匹配:任何一条路由规则匹配成功,会立刻返回结果,后面的路由便没有了响应的机会。

给 ArticleController 增加 show 函数:

 php
public function show($id)
{
    return view('article/show')->withArticle(Article::with('hasManyComments')->find($id));
}

别忘了在顶部引入 Model 类,否则会报类找不到的错误:

php
....
use App\Article;

class ArticleController extends Controller
{
....
    <meta http-equiv="X-UA-Compatible" content="IE=edge">ta http-equiv="X-UA-Compatible" content="IE=edge">
<h4>创建前台文章展示视图</h4>
<p>新建 <code>learnlaravel5/resources/views/article/show.blade.php 文件:
 php



    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Learn Laravel 5 style="text-align: center; margin-top: 50px;">

    <link href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js">
            {{ $article->
    <script src="//cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js">le->
            {{ $article->

    <div id="content" style="padding: 50px;">

        <h4>
            <a href="/"><< 返回首页

        <div id="comments" style="margin-top: 50px;">
        </div>

        <h1 style="text-align: center; margin-top: 50px;">{{ $article->title }}ors) >
        <hr>
        <div id="date" style="text-align: right;">
            {{ $article->updated_at }}
                    <strong>
        <div id="content" style="margin: 20px;">
            <p>
                {{ $article->body }}
             <div id="new">
            <div id="new">

        <div id="comments" style="margin-top: 50px;">

             (count($errors) > 0)
                <div class="alert alert-danger">
                    <strong>操作失败ype="text" name="nickname" class="form-control" style="width: 300px;" required="required"> 输入不符合要求<br><br>
                    {!! implode('<br>', $errors->all()) !!}
                    <div class="form-group">


            <div id="new">
                <form action="{{ url('comment') }}" method="POST">
                    {!! csrf_field() !!}
                    <input type="hidden" name="article_id" value="{{ $article->id }}">
                    <div class="form-group">
                        <label>Nicknameoup">
                        <input type="text" name="nickname" class="form-control" style="width: 300px;" required="required">
                        <textarea name="content" id="newFormContent" class="form-control" rows="10" required="required">
                    <div class="form-group">
                        <label>Email addressass="btn btn-lg btn-success col-lg-12">
                        <input type="email" name="email" class="form-control" style="width: 300px;">
                                <script>
                    <div class="form-group">
                        <label>Home pagen reply(a) {
              var nickname = a.parentNode.parentNode.firstChild.nextSibling.getAttribute('data');
              var textArea = document.getElementById('newFormContent');
              textArea.innerHTML = '@'+nickname+' ';
            }
            </script>
                        <input type="text" name="website" class="form-control" style="width: 300px;">
                    ckname = a.parentNode.parentNode.firstChild.nextSibling.getAttribute('data');
              var textArea = document.getElementById('newFormContent');
              textArea.innerHTML = '@'+nickname+' ';
            }
            
                    <div class="form-group">
                        <label>Content+nickname+' ';
            }
            
                        <textarea name="content" id="newFormContent" class="form-control" rows="10" required="required">rticle->
                    >
                    <button type="submit" class="btn btn-lg btn-success col-lg-12">Submite->
                 class="conmments" style="margin-top: 100px;">
                 ($article->

            <script>
            function reply(a) {
              var nickname = a.parentNode.parentNode.firstChild.nextSibling.getAttribute('data');
              var textArea = document.getElementById('newFormContent');
              textArea.innerHTML = '@'+nickname+' ';
            }
                                 <h3>

            <div class="conmments" style="margin-top: 100px;">
                 ($article->hasManyComments as $comment)

                    <div class="one" style="border-top: solid 20px #efefef; padding: 5px 20px;">
                        <div class="nickname" data="{{ $comment->nickname }}">
                             ($comment->website)
                                <a href="{{ $comment->website }}">
                                    <h3>{{ $comment->nickname }}s="reply" style="text-align: right; padding: 5px;">
                                ss="reply" style="text-align: right; padding: 5px;">

                                <h3>{{ $comment->nickname }}            </div>

                            <h6>{{ $comment->created_at }}/html>
                            </div>
                        <div class="content">
                            <p style="padding: 20px;">
                                {{ $comment->content }}
                            
                        
回复,并增加一条“存储评论”的路由。运行命令:
                        储功能

我们需要创建一个 CommentsController 控制器,并增加一条“存储评论”的路由。运行命令:

                    建一个 CommentsController 控制器,并增加一条“存储评论”的路由。运行命令:



            mentsController 控制器,并增加一条“存储评论”的路由。运行命令:

        ode>

    artisan make:controller CommentController



控制器创建成功,接下来我们增加一条路由:

控制器创建成功,接下来我们增加一条路由:


code>

构建评论存储功能

我们需要创建一个 CommentsController 控制器,并增加一条“存储评论”的路由。运行命令:

 bash
php artisan make:controller CommentController
public function store(Request $request)
{
    if (Comment::create($request->function store(Request $request)
{
    if (Comment::create($request->
<p>控制器创建成功,接下来我们增加一条路由:</p>
<pre><code> php
Route::post('comment', 'CommentController');
    }
}


给这个类增加 store 函数:

 php
public function store(Request $request)
{
    if (Comment::create($request->all())) {
        return redirect()->back();
    } else {
        return redirect()->back()->withInput()->withErrors('评论发表失败!');
    }
}
protected $fillable = ['nickname', 'email', 'website', 'content', 'article_id'];
ed $fillable = ['nickname', 'email', 'website', 'content', 'article_id'];

此处 Comment 类请自己引入。

批量赋值

我们采用批量赋值方法来减少存储评论的代码,

批量赋值中文文档

给 Comment 类增加 $fillable 成员变量:

 php
protected $fillable = ['nickname', 'email', 'website', 'content', 'article_id'];

检查成果

前台文章展示页:

提交几条评论之后:

恭喜你,前台评论功能构建完成!

【大作业】构建后台评论管理功能

评论跟 Article 一样,是一种可以管理的资源列表。2015 版教程的最后,我风风火火地罗列了一堆又一堆的代码,其实对还没入门的人几乎没用。在此,我将这个功能作为大作业布置给大家。大作业嘛,当然是没有标准答案的,但有效果图:

在做这个大作业的过程中,你将会反复地回头去看前面的教程,反复地阅读中文文档,会仔细阅读我的代码,等你完成大作业的时候,Laravel 就真正入门啦~~

该提问来源于开源项目:johnlui/Learn-Laravel-5

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

10条回答

  • weixin_39611382 weixin_39611382 4月前

    没用国内镜像?

    点赞 评论 复制链接分享
  • weixin_39638859 weixin_39638859 4月前

    做完了可以去住范儿吗?

    点赞 评论 复制链接分享
  • weixin_39605455 weixin_39605455 4月前

    可以去住范儿扫地

    点赞 评论 复制链接分享
  • weixin_39855869 weixin_39855869 4月前

    Add [_token] to fillable property to allow mass assignment.

    点赞 评论 复制链接分享
  • weixin_39855869 weixin_39855869 4月前

    好吧 $fillable成员变量要加在comment model里面

    点赞 评论 复制链接分享
  • weixin_39525307 weixin_39525307 4月前

    写的蛮好 作业里 我完成了编辑功能 但是在显示COMMENT所属ARTICLE的标题上有点小问题,如果将两个连起来呢?是用BELONGSTO这个Relationships吗?

    点赞 评论 复制链接分享
  • weixin_39744230 weixin_39744230 4月前

    看完了 感觉tp5 很多借鉴了 laravel的地方

    点赞 评论 复制链接分享
  • weixin_39661353 weixin_39661353 4月前

    感觉博主写的非常好,确实很适合初学者!

    点赞 评论 复制链接分享
  • weixin_39906906 weixin_39906906 4月前

    刚接触laravel 我想知道怎么捕获异常并把异常格式化,方便抛出,看了您写的整个项目没发现有讲这个的。

    点赞 评论 复制链接分享
  • weixin_39915267 weixin_39915267 4月前

    牛逼,半天不到走完整个流程了,就是larvel下包太蛋疼了。

    点赞 评论 复制链接分享

相关推荐