2

从零开始学Laravel目录

读取数据,插入数据我们都学过了,还有一个非常重要的就是更新数据。

我们打开这个链接:http://localhost:8000/posts/2

QQ20161121-0.png

下面我们要做两件事:

  1. 我们要编辑这个评论。

  2. 建立这个评论与用户之间的关系,通常我们要知道是谁发表了这个评论.

好,我们先来做编辑评论的这个功能,简单的流程是我点击这个评论,跳转到编辑评论的页面,然后保存这个评论。

我们先来想一下,显示编辑评论的这个页面的路由该怎么写,通常是这样表达的,我要编辑某个帖子下的某个评论,那可能会这么写:

// 编辑属于帖子ID为3的评论ID为1的评论
// posts/3/comments/1/edit
posts/{post}/comments/{comment}/edit

嗯,上面的路由可以清晰的表达我们想要的意思,能很好的表达出具体功能的意思,但是路径太深了,我们简化下:

Route::get('comments/{comment}/edit', 'CommentsController@edit');

好的,我们到CommentsController中写上edit()方法:

    public function edit(Comment $comment)
    {
        // 加载视图层,并传递$comment数据到视图
        return view('comments.edit', compact('comment'));
    }

然后,我们到pages/show.blade.php中为我们的评论都加上一个编辑的链接:

<ul class="list-group">
    @foreach ($post->comments as $comment)
        <li class="list-group-item">
            {{ $comment->content }}
            <a href="/comments/{{ $comment->id }}/edit">Edit</a>
        </li>
    @endforeach
</ul>

下一步呢,当然是建立我们的comments/edit.balde.php视图层,路径为resources/views/comments/edit.balde.php

@extends('layout')

@section('content')
    <h1>Edit the Comment</h1>

    <form method="{{-- 未知 --}}" action="{{-- 这里的路径现在还没写 --}}">
        {{ csrf_field() }}
        <div class="form-group">
            <textarea name="content" class="form-control">{{ $comment->content }}</textarea>
        </div>

        <div class="form-group">
            <button type="submit" class="btn btn-primary">Update Comment</button>
        </div>
    </form>
@stop

访问:http://localhost:8000/posts/2 点击Edit,跳转到http://localhost:8000/comment...页面,如下:
编辑帖子页

然后当我们点击Update Comment按钮时,这时候我们的路由该怎么写,对于将一条数据存入到数据库,我们用post方式,而对于更新一条数据,我们应该使用patchput方式,我们来写这个路由:

// 更新评论ID为X的评论
Route::patch('comments/{comment}', 'CommentsController@update');

进入CommentsController编写update()方法:

    public function update(Request $request, Comment $comment)
    {
        // update()只会更新Comment模型中$fillable允许的字段
        $comment->update($request->all());

        // 跳转到该评论所属的帖子页
        return redirect('posts/' . $comment->post->id);
    }

下面修改下视图:

@extends('layout')

@section('content')
    <h1>Edit the Comment</h1>

    <form method="POST" action="/comments/{{ $comment->id }}">
        {{ method_field('PATCH') }}
        {{ csrf_field() }}
        <div class="form-group">
            <textarea name="content" class="form-control">{{ $comment->content }}</textarea>
        </div>

        <div class="form-group">
            <button type="submit" class="btn btn-primary">Update Comment</button>
        </div>
    </form>
@stop

上面有一点要注意,我们现在是使用了PATCH的请求,但是表单中的method只能识别getpost方法,所以对于patch, put, delete这些方法,我们要这么写:

    <form method="POST" action="">
        {{ method_field('PATCH') }}
    </form>

当然也可以直接这么写:

    <form method="POST" action="">
        <input type="hidden" name="_method" value="PATCH">
    </form>

我们的编辑评论的最简单的功能做完了,下面我们看下如何为评论添加用户,我们先创建一个users的migration文件,默认安装laravel的时候都是有这个文件的,我们最初把它删除了,现在再来创建一下:

php artisan make:migration create_users_table --create=users 

编辑下这个文件的up()函数:

    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('username')->unique();
            $table->string('email')->unique();
            $table->string('password');
            $table->timestamps();
        });
    }

然后在create_comments_table.php这个migration文件中,添加user_id外键:

$table->integer('user_id')->unsigned()->index();

现在如果我们直接执行php artisan migrate, users表可以被创建,但是我们在comments的migration文件中添加的user_id外键是不会被创建的,对于这种添加一个字段,我们也要单独写一个migration文件。

不过在项目的初期,我们也可以直接更改migration文件,然后执行:

php artisan migrate:refresh

上面这条命令会清空所有的表并重新创建,需慎用, 如果只想撤销上一次的migrate,可以使用php artisan migrate:rollback命令,该命令会执行migration文件中的down()方法。

这里我们执行下php artisan migrate:refresh

我们进入tinker, 重新插入一些数据:

>>> namespace App;
=> null
>>> $user = New User;
=> App\User {#634}
>>> $user->username = 'zhoujiping';
=> "zhoujiping"
>>> $user->email = 'zhoujiping@zhoujiping.com';
=> "zhoujiping@zhoujiping.com"
>>> $user->password = bcrypt('123456');
=> "$2y$10$OM9pBb.xU58hvulnyhq1jeiWPxi8SbddYBW.rhhttEJMraBuVyWdq"
>>> $user->save();
=> true
>>> $post = New Post;
=> App\Post {#627}
>>> $post->title = 'My First Post';
=> "My First Post"
>>> $post->save();
=> true
>>> $comment = New Comment;
=> App\Comment {#639}
>>> $comment->user_id = 1;
=> 1
>>> $comment->content = 'The content of the comment';
=> "The content of the comment"
>>> $post->addComment($comment);
=> App\Comment {#639
     user_id: 1,
     content: "The content of the comment",
     post_id: 1,
     updated_at: "2016-11-21 06:02:33",
     created_at: "2016-11-21 06:02:33",
     id: 1,
   }

我们再到pages/show.blade.php视图,加上用户的用户名:

<ul class="list-group">
    @foreach ($post->comments as $comment)
        <li class="list-group-item">
            {{ $comment->content }}
            <a href="/comments/{{ $comment->id }}/edit">Edit</a>
            <a href="#" class="pull-right">{{ $comment->user->username }}</a>
        </li>
    @endforeach
</ul>

不要忘记去Comment.php中写上评论与用户的关系

    public function user()
    {
        return $this->belongsTo(User::class);
    }

像上面这样写,程序跑通没有问题,但是我们看{{ $comment->user->username }}这条语句会在每次循环的时候都去查询一次用户表信息,导致数据库的查询次数过多,我们看一下:
数据库查询次数

如何解决这个问题呢,laravel提供了热加载和懒加载的方式可以解决这个问题,我们进入到
postsController文件中,修改下show()函数:

    public function show(Post $post)
    {
        $post = Post::with('comments.user')->find($post->id);

       return view('posts.show', compact('post'));
    }

我们看这句话Post::with('comments.user'), 意思是查询的时候加载post的关系comments, 而.user是指加载comments的关系时,还需要加载comments的关系user。 这样就能解决多次查询的问题了。

我们把上面的代码优化下,因为我们已经做了Post的路由模型绑定,我们可以使用懒加载,所以代码改成这样:

    public function show(Post $post)
    {
        $post->load('comments.user');
        
        return view('posts.show', compact('post'));
    }

在看下我们的语句查询次数:
查询次数

关于热加载和懒加载的具体区别,以后再说,大家现在可以不用区分的去使用它们。

好,本节到这里结束。


周继平
386 声望50 粉丝

产品&研发