7

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

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

4 回答 4

17

为了在某​​种导航面板中生成链接,您可以在数据库端进行大部分处理,而不是使用这样的查询获取所有博客文章记录

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

于 2013-05-11T17:01:37.763 回答
16

这是最优雅的方法是将闭包传递给 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
于 2014-03-18T17:06:43.353 回答
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');
                });
        });

然后显示(包括引导程序 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

于 2018-02-14T09:55:41.523 回答
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

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

于 2013-05-11T08:12:34.903 回答