Laravel 5.4 入門系列 10.文章歸檔

心智極客發表於2019-02-16

首先,要實現的是按照日期來統計文章,原始的 SQL 如下:

select 
    year(created_at)  year,
    monthname(created_at) month,
    count(*) published
from posts
group by year, month
order by min(created_at) desc;

將其轉化為 Eloquent Model:

/app/Http/Controllers/PostsController.php
use AppPost;
public function index()
{    

    $archives = Post::selectRaw(`year(created_at)  year, monthname(created_at) month, count(*) published`)
                    ->groupBy(`year`,`month`)
                    ->orderByRaw(`min(created_at) desc`)
                    ->get();

    $posts = Post::latest()->get();

    return view(`posts.index`,compact(`posts`,`archives`));
}

檢視中顯示對應的文章歸檔:

/resources/views/layouts/siderbar.blade.php
  <div class="sidebar-module">
    <h4>Archives</h4>
    <ol class="list-unstyled">
      @foreach ($archives as $archive)
        <li><a href="/posts/?month={{$archive->month}}&&year={{$archive->year}}">{{$archive->month}}&nbsp{{$archive->year}}</a></li>
      @endforeach
    </ol>
  </div>

使用者點選某個月份的時候,向後臺傳入 monthyear 引數,因此 index 方法還需要根據引數型別來進行選擇:

/app/Http/Controllers/PostsController.php
use CarbonCarbon;
public function index()
{    

    $archives = Post::selectRaw(`year(created_at)  year, monthname(created_at) month, count(*) published`)->groupBy(`year`,`month`)->orderByRaw(`min(created_at) desc`)->get();


    $posts = Post::latest();

    if ($month = request(`month`)) {
        $posts->whereMonth(`created_at`,Carbon::parse($month)->month);
    }

    if ($year = request(`year`)) {
        $posts->whereYear(`created_at`,$year);
    }

    $posts = $posts->get();

    return view(`posts.index`,compact(`posts`,`archives`));
}

這裡使用了 Laravel 提供的 whereDate 系列方法,同時,月份用 Carbon 進行轉換。

將上述的一系列查詢進行封裝:

/app/Http/Controllers/PostsController.php
public function index()
{    

    $archives = Post::archives();
    $posts = Post::latest()
                ->filter(request([`year`,`month`]))
                ->get();

    return view(`posts.index`,compact(`posts`,`archives`));
}

模型:

/app/Post.php
use CarbonCarbon;
public function scopeFilter($query, $value)
{
    if ($month = $value[`month`]) {
        $query->whereMonth(`created_at`, Carbon::parse($month)->month);
    }

    if ($year = $value[`year`]) {
        $query->whereYear(`created_at`, $year);
    }
}

public static function archives()
{
    return static::selectRaw(`year(created_at)  year, monthname(created_at) month, count(*) published`)
                ->groupBy(`year`,`month`)
                ->orderByRaw(`min(created_at) desc`)
                ->get();
}

到了這一步,我們基本上實現了文章歸檔的功能。但是有一個問題,文章歸檔實際上包括在通用檢視中,這就意味著,網站的所有請求都需要返回 $archives,否則就會報錯。一種做法就是在不同方法下都呼叫 archives() 方法來返回資料。當然,更為簡單的方法就是使用「檢視共享資料」功能。操作如下:

/app/Providers/AppServiceProvider.php
public function boot()
{
    Schema::defaultStringLength(191);
    view()->composer(`layouts.siderbar`,function($view){

        $view->with(`archives`,AppPost::archives());

    });
}

該服務提供者包含兩個方法:register(),用來繫結 IOC 容器(先忽略),繫結完之後,我們就可以在 boot 裡面定義我們想要實現的功能了,在該例中,我們註冊了 layouts.siderbar 檢視,並傳遞給檢視 archives 變數。


相關文章