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

Posted

技术标签:

【中文标题】在 Laravel 中为博客生成归档列表【英文标题】:Generating archive list for a blog in Laravel 【发布时间】:2013-05-05 21:06:35 【问题描述】:

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

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

我该如何实现上述目标?

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

谢谢。 SQL 查询有效,但我认为这不是 Laravel 中原始查询的方式,所以它不起作用。【参考方案2】:

这是最优雅的方法是将闭包传递给 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

【讨论】:

非常优雅!默认情况下有一个问题,排序是 asc !从 2013 年、2014 年等开始……如何在 desc 中对其进行排序? 我找到了解决方案:News::orderBy('created_at', 'desc')->get()->groupBy(function($date) 这并没有完全返回 OP 所要求的内容,他想要一个包含每个月的帖子数的月份列表,而这会返回帖子本身,以月为单位进行组织。确实可以在这里使用count() 来解决这个问题,但是它仍然会返回很多不需要的信息……但也许它仍然比自定义 SQL 查询更快?不知道...【参考方案3】:

我也被困了一段时间。通过使用更多 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

【讨论】:

【参考方案4】:

我认为你很接近,但你需要测试数据,这是你的要求吗?

您也可以查询数据。

我并不是说这是解决问题的唯一方法,但是这将如何工作? 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

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

【讨论】:

以上是关于在 Laravel 中为博客生成归档列表的主要内容,如果未能解决你的问题,请参考以下文章

php laravel框架学习笔记 基本工作原理

如何在 laravel 中为列表或数组定义策略?

分类

我想自学laraver,请诸位前辈给一些建议,谢谢

我如何在 laravel 中为 spatie 包(ACL 管理)中的其他角色分配用户列表权限?

Laravel基础教程