在Laravel中为博客生成存档列表

时间:2013-05-11 07:22:46

标签: php sql laravel

我正在尝试为博客文章生成归档列表。存档列表应按反向时间顺序显示年份和日期,如下所示:

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));
}

我如何实现上述目标?

4 个答案:

答案 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

继续阅读有关多态性和查询关系,动态属性......