我正在尝试为博客文章生成归档列表。存档列表应按反向时间顺序显示年份和日期,如下所示:
2013 (21)
- May (2)
- April (3)
- March (5)
- February (1)
- January (10)
2012 (10)
- December (6)
- November (4)
()
内的数字是该时间段内的帖子数。选择一年中的年份或月份后,只应显示所选时间段内的博客文章。
到目前为止,我只能通过以下方式查找每篇博文的年份和月份:
$posts = Post::all();
$archive = array();
foreach ($posts as $post) {
$year = date('Y', strtotime($post->created_at));
$month = date('m', strtotime($post->created_at));
}
我如何实现上述目标?
答案 0 :(得分:14)
为了在某种导航面板中生成链接,您可以在数据库端执行大部分处理,而不是使用像这样的查询获取所有博客帖子记录
SELECT YEAR(created_at) year,
MONTH(created_at) month,
MONTHNAME(created_at) month_name,
COUNT(*) post_count
FROM post
GROUP BY year, MONTH(created_at)
ORDER BY year DESC, month DESC;
输出:
| YEAR | MONTH | MONTH_NAME | POST_COUNT |
------------------------------------------
| 2013 | 5 | May | 5 |
| 2013 | 4 | April | 3 |
| 2013 | 3 | March | 4 |
| 2013 | 2 | February | 3 |
| 2013 | 1 | January | 2 |
| 2012 | 12 | December | 2 |
| 2012 | 11 | November | 3 |
我不是laravel的专家,但应该通过与此类似的东西实现。
$links = DB::table('post')
->select(DB::raw('YEAR(created_at) year, MONTH(created_at) month, MONTHNAME(created_at) month_name, COUNT(*) post_count'))
->groupBy('year')
->groupBy('month')
->orderBy('year', 'desc')
->orderBy('month', 'desc')
->get();
如果您愿意,可以将小计添加到像这样的年份行
SELECT YEAR(created_at) year,
MONTH(created_at) month,
MONTHNAME(created_at) month_name,
COUNT(*) post_count
FROM post
GROUP BY year, MONTH(created_at)
UNION ALL
SELECT YEAR(created_at) year,
13 month,
NULL month_name,
COUNT(*) post_count
FROM post
GROUP BY year
ORDER BY year DESC, month DESC;
输出:
| YEAR | MONTH | MONTH_NAME | POST_COUNT |
------------------------------------------
| 2013 | 13 | (null) | 17 |
| 2013 | 5 | May | 5 |
| 2013 | 4 | April | 3 |
| 2013 | 3 | March | 4 |
| 2013 | 2 | February | 3 |
| 2013 | 1 | January | 2 |
| 2012 | 13 | (null) | 5 |
| 2012 | 12 | December | 2 |
| 2012 | 11 | November | 3 |
<强> SQLFiddle 强>
答案 1 :(得分:14)
这样做最优雅的方法是将闭包传递给groupBy()集合方法。
$posts_by_date = Post::all()->groupBy(function($date) {
return Carbon::parse($date->created_at)->format('Y-m');
});
然后,您可以在刀片模板中循环浏览它,类似于:
@foreach ($posts_by_date as $date => $posts)
<h2>{{ $date }}</h2>
@foreach ($posts as $post)
<h3>{{ $post->title }}</h3>
{{ $post->content }}
@endforeach
@endforeach
答案 2 :(得分:2)
我也被困在这一段时间了。通过使用更多laravel功能,我得出了以下解决方案:
创建档案:
$archive = Post::orderBy('created_at', 'desc')
->whereNotNull('created_at')
->get()
->groupBy(function(Post $post) {
return $post->created_at->format('Y');
})
->map(function ($item) {
return $item
->sortByDesc('created_at')
->groupBy( function ( $item ) {
return $item->created_at->format('F');
});
});
然后显示(包括bootstrap 4类):
<div class="archive mt-5">
<h4>Archive</h4>
@foreach($archive as $year => $months)
<div>
<div id="heading_{{ $loop->index }}">
<h6 class="mb-0">
<button class="btn btn-link py-0 my-0" data-toggle="collapse"
data-target="#collapse_{{ $loop->index }}"
aria-expanded="true"
aria-controls="collapse_{{ $loop->index }}">
>
</button>
{{ $year }}
</h6>
</div>
<div id="collapse_{{ $loop->index }}" class="collapse" aria-labelledby="heading_{{ $loop->index }}"
data-parent="#accordion">
<div>
<ul style="list-style-type: none;">
@foreach($months as $month => $posts)
<li class="">
{{ $month }} ( {{ count($posts) }} )
</li>
@endforeach
</ul>
</div>
</div>
</div>
@endforeach
答案 3 :(得分:0)
我认为你很接近,但你需要测试数据,这就是你要问的吗?
您也可以查询数据。
我不是说这是解决问题的唯一方法,但这怎么办? for each语句可以将数据存储到数组中,如下所示:
function checkdate($datein,$posts){
foreach ($posts as $post){
$year = date('Y', strtotime($post->created_at)))
$month = date('m', strtotime($post->created_at)))
if(($year == $datein->year)||($month == $datein->month)){
//good
}
else {
//bad
}
}
}
那就可以了,但是......如果我们首先过滤了数据怎么办?我敢打赌Laravel有更好的方法来处理它。
是的! http://four.laravel.com/docs/eloquent#query-scopes
继续阅读有关多态性和查询关系,动态属性......