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

相關文章
相關標籤/搜索