首先,要實現的是按照日期來統計文章,原始的 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}} {{$archive->year}}</a></li>
@endforeach
</ol>
</div>
使用者點選某個月份的時候,向後臺傳入 month
和 year
引數,因此 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
變數。