Laravel 5系列教程九:Eloquent Relationship

原文来自 https://laravist.com/article/18javascript

免费视频教程地址 https://laravist.com/series/laravel-5-basic

Laravist是我刚刚上线的Laravel社区,有任何与Laravel相关的问题能够到这里来问我,我会尽力去帮你们解决问题,后期会尝试录制一些视频教程,形式大概是这样的php

https://laravist.com/lesson/1css

前奏

在开始正文以前,咱们首先来讲说在实际的开发中,常常会接触到几种常见的对应关系模式:html

One-To-One //一对一

One-To-Many //一对多

Many-To-Many //多对多

不知道你对这些概念是一种什么样的感觉,若是是不太理解的。你能够将这些概念应用到生活中,理解起来就很简单了,就举一个与咱们在网上常常见到的例子:java

User-To-Profile // One-To-One

User-To-Articles // One-To-Many

Article-To-Comments // One-To-Many

Articles-To-Tags // Many-To-Many

翻译过来就是:jquery

  1. 一个用户对应一个用户档案laravel

  2. 一个用户能够发表多篇文章git

  3. 一篇文章能够有多个评论github

  4. 而文章和标签确实多对多的关系,一篇文章能够有多个标签;一个标签能够属于多篇文章数据库

在这些关系模型中,最难实现的就是Many-To-Many这种多对多的关系,可是咱们这个简单地博客并无用户管理,也就是并无开放让用户注册,因此咱们在这里仍是要挑战一下难度,实现Articles-To-Tags这种Many-To-Many关系,借助Laravel的强大的Eloquent,实现这个功能仍是比较顺心的。至于一对一和一对多这两种关系,能够举一反三。

建立tags表

要实现Articles-To-Tags这种Many-To-Many关系,咱们须要tags表和Tag模型,因此咱们分别来建立之。

php artisan make:migration create_tags_table --create=tags

打开生成的migration文件,为up()方法增长一行代码:

public function up()
{
    Schema::create('tags', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });
}

这里咱们增长了$table->string('name');这一行,这个字段表示为tags table添加一个name字段,表明标签的名字。

接下来,咱们为tags表建立一个Tag模型:

php artisan make:model Tag

生成了Tag模型以后,咱们先不用去管Tag.php文件,由于咱们还须要一张关系表article_tag,这个表只存tag_idarticle_id,因此咱们来建立之:

php artisan make:migration create_article_tag_table --create=article_tag

打开migration文件来为之加上tag_idarticle_id这两个字段:

public function up()
    {
        Schema::create('article_tag', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('article_id')->unsigned()->index();
            $table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');
            $table->integer('tag_id')->unsigned()->index();
            $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
            $table->timestamps();
        });
    }

这里貌似就添加tag_id和article_id这两个字段,可是用了不少行代码,咱们只要是理解下面这个:

$table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');

foreign():外键
references():参照字段
on():参照表
onDelete():删除时的执行动做
这里是跟着删除,好比删除了某篇文章,咱们将article_tag中包含article_id同样的记录也删除

最后,执行migration生成article_tag表:

php artisan migrate

OK,生成这两个表以后,咱们就能够正式开始咱们的工做了。

声明Eloquent的关系

Articles和Tags是多对多的关系,因此咱们须要在Article.php中声明下面的关系:

public function tags()
    {
        return $this->belongsToMany('App\Tag');
    }

在Tag.php,也一样:

public function articles()
    {
        return $this->belongsToMany('App\Article');
    }

咱们使用$this->belongsToMany()来代表Eloquent的关系,这里须要注意的是若是你的外键并非article_idtag_id,你须要在第三个参数进行设置,写成相似下面这样:

public function articles()
    {
        return $this->belongsToMany('App\Article','conversation_id');
    }

OK,这样,咱们的多对多关系就声明完毕了。

使用Select2

在开始以前,咱们使用tinker生成几个tag,过程就不演示了,最后是这样的:

替代文字

而后,为了更好地用户体验,咱们引入Select2,这个对选择多个选项的时候表现得异常完美。

Select2 用法:https://select2.github.io/examples.html

咱们在app.blade.php引入Select2的css文件和js文件:

<link rel='stylesheet' href="/css/select2.css" type='text/css' media='all'/>
<script src="/js/jquery-2.1.0.min.js"></script>
<script src="/js/select2.full.min.js"></script>

在<head></head>标签内,咱们还引入了jquery,由于select2依赖于jquery,因此。注意文件的下载或来源,请自行获取。

引入以后,咱们就能够在文件建立的页面依旧使用咱们的Form来生成咱们的选择框了,来到articles/create.blade.php文件,在published_at下面添加一个输入表单:

<div class="form-group">
        {!! Form::label('tag_list','选择标签') !!}
        {!! Form::select('tag_list[]',$tags,null,['class'=>'form-control js-example-basic-multiple','multiple'=>'multiple']) !!}
</div>

这里须要注意的是tag_list[],若是咱们只是使用tag_list,就只能选到一个标签,若是咱们须要选择多个,咱们须要已数组的形式来储存咱们的标签,还有一个就是指定一下'multiple'=>'multiple',就是开启支持多选模式。而后$tags就是咱们须要从数据库获tags表取到得数据,因此天然而然,咱们到ArticleController中的create()方法中,稍微修改一下代码:

public function create()
    {
        $tags = Tag::lists('name', 'id');
        //为了在界面中显示标签name,id为了在保存文章的时候使用。
        return view('articles.create',compact('tags'));
    }

这里咱们使用lists()方法将Tag中(对于tags数据表)name和id以一个Eluqoent的方式返回,你可使用dd($tags),来看看。恩,这个时候来看看咱们的create页面:

替代文字

这时候咱们发现,样式并无Select2那么好看,那是由于咱们尚未初始化Select2,因此咱们在create.blade.php写几行简单地js代码:

<script type="text/javascript">
        $(function() {
            $(".js-example-basic-multiple").select2({
                placeholder: "添加标签"
            });
        });
    </script>

@endsection紧接着的上一行加上上面的代码,这里咱们使用jquery的选择器,而后调用select2();来初始化咱们的选择框,再来看看效果:

替代文字

很完美,咱们将整个UI完善得还不错,咱们用dd();来看看咱们表单提交过来的是什么,在ArticleController中的store()方法中添加一行代码:

dd($request->all());

咱们来看看效果:

替代文字

咱们看到得tag_list是一个数组,里面的值并非咱们选择的标签的name,而是标签的id,这样咱们就可使用laravel提供的attach()来添加咱们的标签了,这个attach()接受一个id的数组,这里正好!,因此咱们来稍微来修改一下store()方法:

public function store(Requests\StoreArticleRequest $request)
    {
        $input = $request->all();
        $input['intro'] = mb_substr($request->get('content'),0,64);
        $article = Article::create($input);
        $article->tags()->attach($request->input('tag_list'));
        return redirect('/');
    }

咱们这里首先将Article::create($input)赋予$article变量(Eloquent对象),而后使用$article->tags()->attach()来添加标签,并将咱们的标签数组传给attach()方法,咱们来看看有没有成功:

替代文字

这里的文章是发表成功了,咱们再来看看咱们的标签是否添加成功,来看看咱们的article_tag表:

替代文字

是添加了三个标签,可是咱们发现这个created_atupdated_at貌似有点问题,咱们来修复一下,在Article.php中的tags()方法中:

public function tags()
    {
        return $this->belongsToMany('App\Tag')->withTimestamps();
    }

咱们在后面直接使用withTimestamps()来同步咱们的时间,咱们再来试一试:

替代文字

再来看看咱们的数据库:

替代文字

看到最后的两个记录,很完美。

在视图中显示咱们的tags

咱们既然有了标签,咱们为何不来将它展现出来呢?在articles/index.blade.php中,咱们来将文件的标签输出一下:

<h2 class="post-title pad">
    <a href="/articles/{{ $article->id }}"> {{ $article->title }}</a>
</h2>
<ul class="post-meta pad group">
    <li><i class="fa fa-clock-o"></i>{{ $article->published_at->diffForHumans() }}</li>
    @if($article->tags)
        @foreach($article->tags as $tag)
            <li><i class="fa fa-tag"></i>{{ $tag->name }}</li>
        @endforeach
    @endif
</ul>

咱们在<h2>标签下面增长一个<ul>列表,而后是首先将发表日期published_at输出了,这里咱们使用了Carbon的diffForHumans()方法,这个方法就会产生几分钟以前,几个小时以前的效果,这里也能够体会咱们以前须要将published_at这个对象做为Carbon对象来对待了,若是是简单地字符串,是不能调用Carbon的diffForHumans()方法的。

接下来,咱们使用$article->tags取得文章的标签,这个tags就是咱们声明多对多关系的tags()方法。咱们来看看效果:

替代文字

咱们发现咱们的多少分钟以前都是英文,那是由于咱们没有设置Carbon,咱们来修复一下,在app/Providers/AppServiceProvider.php中的boot()方法添加下面这一行:

\Carbon\Carbon::setLocale('zh');

而后刷新,见证一下奇迹吧:

替代文字

总结

到这里咱们利用laravel提供的attach()方法将基本的多对多关系实现了,而且还稍微美化了一下输出,将published_at字段完美呈现。接下来我打算说一说怎么实现修改文章了,这是一个必走的流程嘛。因此。。。

最后,Happy Hacking

相关文章
相关标签/搜索