Laravel教程 五:MVC的基本流程

JellyBool

JellyBool

期间受到很多私事影响,终于还是要好好写写laravel的教程了。

上一篇我们说了数据库和Eloquent的基本用法,如计划一样,这一篇文章我们说说Laravel中Model,Controller,Views的工作流程,也就是下面这个顺序:

1.注册路由 ---> 2.创建控制器 ---> 3. 控制器中获取数据库数据 ---> 4.在视图中展示数据

英文的表达可能会更加贴切一点:

1.register routes ---> 2.make a controller ---> 3.fetch data from database ---> 4. load a view to display data

在laravel中,最常见的流程就是这个样子的,我们在实现某个功能的时候,通常就是走上面的这个流程。比如我们这个blog项目中,我们需要实现下面的功能:

1. 展示所有的文章  // blog首页
2. 展示一篇文章   //文章详情页
3. 创建一篇文章   // 文章发布页面
4. 修改一篇文章  // 文章修改页面
5. 删除一篇文章  // 后台管理

在这一篇文章中,我们集中精力解决一下第一个功能,所以我们按照上面的流程来走一遍:

PS : 上次我们使用artisan tinker这个工具在命令行中对数据库的数据进行了CRUD,现在就要将这些应用到MVC当中了。

注册路由

我们这里会从头开始,也就是会先删除app/Http/Controllers/ArticleController.php这个文件

在系列文章的第二篇当中,我们在app/Http/routes.php中注册了我们首页的路由:

Route::get('/','ArticleController@index');

可以直接使用这个路由,所以我们可以进入下一步。

创建控制器

这里需要注意的是,如果你使用了Homestead,请先ssh登录到你的虚拟机中执行命令;还有就是,请先删除之前课程遗留的ArticleController,如果你想偷懒,可以跳过这一步

创建控制器的时候你可以手动创建,不过还是推荐使用artisan这个命令行工具,在项目目录之下,命令行执行:

php artisan make:controller ArticleController --plain

这里需要说明的是--plain这个参数表明只要一个简单的controller,里面不需要生成一堆如show(),create()等方法。

控制器中获取数据库数据

打开这个重新创建的ArticleController.php:

class ArticleController extends Controller
{

    public function index()
    {
        $articles = Article::all();

        return $articles;
    }
}

我们创建一个index()方法,这是因为我们在routes.php当中注册的路由指定要加载ArticleControllerindex()方法,我们在index()方法中使用Article::all()将数据库中articles这张表中的所有的记录查找出来,直接返回。

我们用浏览器来访问试试,会看到类似下面这个情况:

替代文字

对,如你看到的一样,如果你直接返回查找到得数据,Laravel会默认将这些数据转换成json格式,因为laravel可能是出于这样的考虑:一般这种情况下地返回,通常都是在创建api功能,比如你为你的一个手机App写的api一样,json数据无疑是很好的选择。

顺便安利一下大家使用百度团队的这个FeHelper这个chrome插件:

https://github.com/zxlie/FeHelper

但是在这里我们并不是想直接返回json,取而代之的是,我们的目的是加载视图,将数据展示出来。所以这就是我们下一步的工作了

在视图中展示数据

这里我们首先需要修改的是ArticleController中的index()方法:

public function index()
{
    $articles = Article::all();

    return view('articles.index',compact('articles'));
}

我们只是修改了return这一行的代码,使用view()方法加载视图,这个视图就是位于resources/views/articles/中的index.blade.php(我们还没有创建),最后使用compact('articles')将数据传给视图文件:关于这个视图传递变量的问题,你可以参考教程的第三篇

然后,我们需要创建我们的视图文件,在resources/views/articles/下创建index.blade.php文件:

@extends('app')
@section('content')
 <h1>这是index.blade.php</h1>
@endsection

写上上面的内容,关于视图文件的blade模板,可以参考教程的第三篇,然后浏览器访问一下看看:

替代文字

视图文件正确之后,我们需要将传递给视图的$articles变量的内容展示出来:

@extends('app')
@section('content')
    @foreach($articles as $article)
        <h1>{{ $article->title }}</h1>
        <p>{{ $article->intro }}</p>
        <hr>
    @endforeach
@endsection

我们使用@foreach来将所有的文章循环出来,浏览器访问看看:

替代文字

这里我们的首页展示也就基本完成了,然而在我们的实际blog中,我们会在每个标题出给出我们的文章链接,也就是为每个文章添加一个详情展示的页面,用户点击文章的链接之后,我们展示相应的文章详情。我们来实现这个功能

显示文章详情

通过文章展示来快速体验上面的流程:

1.注册路由

来到app/Http/routes.php中,我们增加一个路由:

Route::get('articles/{id}','ArticleController@show');

上面的路由articles/{id}指定我们需要加载ArticleController中的show()方法。这里需要注意的是{id}这个表达:这是表示id是一个路由变量,也就是当我们访问类似下面这两个路由的时候:

http://blog.dev/articles/1 //id 为1
http://blog.dev/articles/foo // id为foo

先不急着访问,因为我们还没有创建show()方法,这里只是作为说明。

在laravel中,路由变量写在{}括号中,这个id对应我们等下写的show()方法的参数。

2.编写show()

在ArticleController增加show()方法:

public function show($id)
{
    return $id;
}

我们在show($id)方法中,首先接受参数id,然后直接返回。现在我们可以访问上面的两个url了,看到的类似下面这个效果:

替代文字

3.获取数据

然而在show()方法中,我们也是需要从数据库中加载获取数据,所以我们先修改show()方法:

public function show($id)
{
    $article = Article::find($id);
    return $article;
}

我们通过find()方法从数据库中查找一条记录,然后直接返回,我们来看看效果:

替代文字

4.加载视图

获取数据之后,我们需要加载相应地视图来展示数据,还是修改show()方法:

public function show($id)
{
    $article = Article::find($id);
    return view('articles.show',compact('article'));
}

类似地,我们使用view()加载show.blade.php,然后compact()将变量传递过去。所以我们去创建show.blade.php视图文件吧:

@extends('app')
@section('content')
        <h1>{{ $article->title }}</h1>
        <hr>
        <p>{{ $article->content }}</p>
@endsection

这里跟index.blade.php视图文件差不多,我们只是去掉了@foreach,在来访问一下看看:

替代文字

到这里,我们的文章展示页面也可以说是完成了,然而当我们访问这个下面这个链接的时候:

http://blog.dev/articles/3

报错了!

替代文字

这是因为我们在show()方法中使用$article = Article::find($id);来查找一篇文章,但是我们的数据库中的articles表并没有id3的记录,也就是id3的时候,$article变量已经是null了,这个时候我们如果还是希望在视图中使用{{ $article->title }},所以才会出现错误:

Trying to get property of non-object.... 

PS: 如果你想调试,看看$article到底是什么,你可以在laravel中使用dd($article)来调试

那这个要怎么解决呢?有两种方法:

第一,自己写个if条件判断:

public function show($id)
   {
       $article = Article::find($id);
       if(is_null($article)){
           abort(404);
       }
       return view('articles.show',compact('article'));
   }

如果$article为空,直接abort()一个404页面。再来访问一下:

替代文字

这里貌似还是会看到一堆错误,为什么呢?那是因为在.env中我们设置了APP_DEBUG=true,所以还会有下面的一堆错误,我们在实际的线上部署环境中,APP_DEBUG=false才是我们的设置。我们来体验一把将APP_DEBUG=false,见证一下我们的404页面:

替代文字

这个404页面,你可以自定义:就是在resources/views/errors/文件夹下创建一个404.blade.php

实际例子就是这样的(彩蛋):

https://jellybool.com/show404page

你也可以在我的blog地址栏随便输入一堆东西,看看找不到文章的时候是什么样的404 page 。

第二,使用findOrFail()

上面的条件判断其实很不错了,但是这里我还是推荐使用findOrFail()这个方法:

public function show($id)
    {
        $article = Article::findOrFail($id);
       
        return view('articles.show',compact('article'));
    }

findOrFail()表示首先尝试find,如果找不到就fail,抛出一个Eloquent Exception,所以我们再来访问尝试一下:

替代文字

我们应该会得到一样的结果.

然后我们回到我们的index.blade.php中为每篇文章添加链接:

  @foreach($articles as $article)
      <h1><a href="/articles/{{ $article->id }}">{{ $article->title }}</a></h1>
      <p>{{ $article->intro }}</p>
      <hr>
  @endforeach

访问来看看:

替代文字

注意我们这里直接使用了href="/articles/{{ $article->id }}"进行链接,你也可以使用action()这个方法:

 @foreach($articles as $article)
        <h1><a href="{{ action('ArticleController@show',[$article->id]) }}">{{ $article->title }}</a></h1>
        <p>{{ $article->intro }}</p>
        <hr>
    @endforeach

action()这个方法第一个参数表明要加载ArticleControllershow()方法,跟routes一样,第二个参数用数组传入相应地参数[$article->id]

你还有第三种选择,使用url()方法:

@foreach($articles as $article)
      <h1><a href="{{ url('articles/',$article->id) }}">{{ $article->title }}</a></h1>
      <p>{{ $article->intro }}</p>
      <hr>
  @endforeach

url()方法第一个参数传入url路径,第二个参数直接传入变量。

上面的三种方法,选择一种自己喜欢的就可以了。

下一节

就写到这里吧,这一节大概也就是这样的内容了,不知道这样介绍,大家对Laravel的Model Controller Views的工作流程清晰了没,不清晰的话可以评论问我。。。

下一节,我即将说说怎么实现创建一篇文章,就会顺带介绍Laravel的Forms表单。

最后,

Happy Hacking

本文由 JellyBool 创作, 转载和引用遵循 署名-非商业性使用 2.5 中国大陆 进行许可。

共有 85 条评论

openwrtmail
修改的评论也不能少于六个字哦!
openwrtmail
修改的评论也不能少于六个字哦!
hlhsbczd123 回复 openwrtmail
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
TimeIsGoOn
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
TimeIsGoOn
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
TimeIsGoOn
修改的评论也不能少于六个字哦!
TimeIsGoOn
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
TimeIsGoOn
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
richardxxx0x
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
richardxxx0x
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
richardxxx0x
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
mailman
修改的评论也不能少于六个字哦!
mailman
修改的评论也不能少于六个字哦!
mailman
修改的评论也不能少于六个字哦!
codekissyoung
修改的评论也不能少于六个字哦!
codekissyoung
修改的评论也不能少于六个字哦!
jeak84
修改的评论也不能少于六个字哦!
JellyBool
修改的评论也不能少于六个字哦!
jeak84
修改的评论也不能少于六个字哦!
jeak84
修改的评论也不能少于六个字哦!
jeak84
修改的评论也不能少于六个字哦!
rootx
修改的评论也不能少于六个字哦!
DavidWang
修改的评论也不能少于六个字哦!
frankstar
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
BiggerHeader 回复 Anonymous
修改的评论也不能少于六个字哦!
BiggerHeader 回复 Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
一心为谁
修改的评论也不能少于六个字哦!
JellyBool 回复 一心为谁
修改的评论也不能少于六个字哦!
xyj7473423
修改的评论也不能少于六个字哦!
JellyBool 回复 xyj7473423
修改的评论也不能少于六个字哦!
xyj7473423 回复 JellyBool
修改的评论也不能少于六个字哦!
xyj7473423
修改的评论也不能少于六个字哦!
vartist
修改的评论也不能少于六个字哦!
JellyBool 回复 vartist
修改的评论也不能少于六个字哦!
vartist 回复 JellyBool
修改的评论也不能少于六个字哦!