如何在 Laravel Eloquent 中限制和分页查询结果

在本系列中,您一直在向您的演示应用程序添加新的链接,以测试Laravel Eloquent的几个功能。您可能注意到主索引页面每次添加新链接时都会变得更长,因为在应用程序中显示的链接数量没有限制。

在本系列中,您将学习如何使用limit()方法限制 Laravel Eloquent 查询中的结果数量,以及如何使用SimplePaginate()方法页面化结果。

限制 Query 结果

要开始,您将更新您的主要应用路线(/),以限制在您的索引页面上列出的链接的数量。

首先,在您的代码编辑器中打开您的 Web 路由文件:

1routes/web.php

然后,找到主要路线定义:

1[label routes/web.php]
2Route::get('/', function () {
3    $links = Link::all()->sortDesc();
4    return view('index', [
5        'links' => $links,
6        'lists' => LinkList::all()
7    ]);
8});

突出的行显示了通过链接模型all()方法获取数据库中的所有链接的查询,正如本系列的上一部分所解释的那样,该方法是从模型类继承的,并返回一组包含与该模型相关联的所有数据库记录的集合。

现在,您将更改突出的行,以使用数据库查询排序方法 orderBy(),该方法在数据库级别上排序查询结果,而不是简单地通过 all() 方法将返回为 Eloquent Collection 的整个行组重新排序。

用以下代码更换您的主要路线,以便您方便地进行更改:

1[label routes/web.php]
2Route::get('/', function () {
3    $links = Link::orderBy('created_at', 'desc')->limit(4)->get();
4
5    return view('index', [
6        'links' => $links,
7        'lists' => LinkList::all()
8    ]);
9});

更新后的代码现在会将最新的 4 个链接添加到数据库中,无论哪个列表。

接下来,您将学习如何页面化结果,以确保所有链接仍然可访问,即使它们不会同时在单个页面上加载。

搜索结果 查询结果

您的索引页面现在限制了列出的链接的数量,以便您的页面不会被内容过载,并在更短的时间内进行渲染。虽然这种解决方案在许多情况下工作得很好,但您需要确保访问者仍然可以访问旧链接,这些链接默认不见。

Laravel Eloquent 具有原生方法,可方便对数据库查询结果实施页面化,而paginate()simplePaginate()方法则负责生成页面化链接,处理 HTTP 参数来识别当前所请求的页面,并对数据库进行查询以获得预期结果的正确限制和抵消,这取决于您想要列出的页面上记录的数量。

现在,您将更新routes/web.php中的 Eloquent 查询以使用simplePaginate()方法,该方法会生成具有 以前接下来的链接的基本导航。

在代码编辑器中打开 routes/web.php 文件,开始更新 / 路线,用 simplePaginate() 代替 limit(4)->get() 方法调用:

 1[label routes/web.php]
 2...
 3Route::get('/', function () {
 4    $links = Link::orderBy('created_at', 'desc')->simplePaginate(4);
 5
 6    return view('index', [
 7        'links' => $links,
 8        'lists' => LinkList::all()
 9    ]);
10});
11...

接下来,在相同的文件中找到/{slug}路径定义,并用simplePaginate()方法替换get()方法。

 1[label routes/web.php]
 2...
 3Route::get('/{slug}', function ($slug) {
 4    $list = LinkList::where('slug', $slug)->first();
 5    if (!$list) {
 6        abort(404);
 7    }
 8
 9    return view('index', [
10        'list' => $list,
11        'links' => $list->links()->orderBy('created_at', 'desc')->simplePaginate(4),
12        'lists' => LinkList::all()
13    ]);
14})->name('link-list');
15...

这就是你完成后完成的 routes/web.php 文件的样子。

 1[label routes/web.php]
 2<?php
 3
 4use Illuminate\Support\Facades\Route;
 5use App\Models\Link;
 6use App\Models\LinkList;
 7
 8/*
 9|--------------------------------------------------------------------------
10| Web Routes
11|--------------------------------------------------------------------------
12|
13| Here is where you can register web routes for your application. These
14| routes are loaded by the RouteServiceProvider within a group which
15| contains the "web" middleware group. Now create something great!
16|
17*/
18
19Route::get('/', function () {
20    $links = Link::orderBy('created_at', 'desc')->simplePaginate(4);
21
22    return view('index', [
23        'links' => $links,
24        'lists' => LinkList::all()
25    ]);
26});
27
28Route::get('/{slug}', function ($slug) {
29    $list = LinkList::where('slug', $slug)->first();
30    if (!$list) {
31        abort(404);
32    }
33
34    return view('index', [
35        'list' => $list,
36        'links' => $list->links()->orderBy('created_at', 'desc')->simplePaginate(4),
37        'lists' => LinkList::all()
38    ]);
39})->name('link-list');

完成后保存文件。

数据库查询现在已更新,但您仍然需要更新前端视图以包含将导航栏渲染的代码. 由 simplePaginate() 获得的 Eloquent 集合包含一种称为 links() 的方法,可以从前端视图调用以输出必要的 HTML 代码,该代码将基于页面的 Eloquent 查询进行导航。

您还可以使用页面的 Eloquent 集合中的链接()方法访问固有的 Paginator 对象,该对象提供了几种 有用的方法来获取有关内容的信息,例如当前页面,以及是否有多个内容页面。

在您的代码编辑器中打开resources/views/index.blade.php应用程序视图:

1resources/views/index.blade.php

查找标记为链接的部分的尽头,其中包含链接渲染的前方循环,在该部分之后并在该页面上最后的</div>标签之前放置以下代码:

1[label resources/views/index.blade.php]
2        @if ($links->links()->paginator->hasPages())
3            <div class="mt-4 p-4 box has-text-centered">
4                {{ $links->links() }}
5            </div>
6        @endif

此代码通过访问 Paginator 对象并调用 hasPages() 方法来检查结果的多个页面是否存在.当该方法返回 true 时,页面会返回一个新的 div 元素,并调用 links() 方法来打印相关 Eloquent 查询的导航链接。

以下是更新后的index.blade.php页面,一旦完成,它将是这样的:

 1[label resources/views/index.blade.php]
 2<!DOCTYPE html>
 3<html>
 4<head>
 5    <meta charset="utf-8">
 6    <meta name="viewport" content="width=device-width, initial-scale=1">
 7    <title>My Awesome Links</title>
 8    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css">
 9
10    <style>
11        html {
12            background: url("https://i.imgur.com/BWIdYTM.jpeg") no-repeat center center fixed;
13            -webkit-background-size: cover;
14            -moz-background-size: cover;
15            -o-background-size: cover;
16            background-size: cover;
17        }
18
19        div.link h3 {
20            font-size: large;
21        }
22
23        div.link p {
24            font-size: small;
25            color: #718096;
26        }
27    </style>
28</head>
29<body>
30<section class="section">
31    <div class="container">
32        <h1 class="title">
33            @if (isset($list))
34                {{ $list->title }}
35            @else
36                Check out my awesome links
37            @endif
38        </h1>
39        <p class="subtitle">
40            @foreach ($lists as $list)<a href="{{ route('link-list', $list->slug) }}" title="{{ $list->title }}" class="tag is-info is-light">{{ $list->title }} ({{ $list->links()->count() }})</a> @endforeach
41        </p>
42
43        <section class="links">
44            @foreach ($links as $link)
45                <div class="box link">
46                    <h3><a href="{{ $link->url }}" target="_blank" title="Visit Link: {{ $link->url }}">{{ $link->description }}</a></h3>
47                    <p>{{$link->url}}</p>
48                    <p class="mt-2"><a href="{{ route('link-list', $link->link_list->slug) }}" title="{{ $link->link_list->title }}" class="tag is-info">{{ $link->link_list->title }}</a></p>
49                </div>
50            @endforeach
51        </section>
52
53        @if ($links->links()->paginator->hasPages())
54            <div class="mt-4 p-4 box has-text-centered">
55                {{ $links->links() }}
56            </div>
57        @endif
58    </div>
59</section>
60</body>
61</html>

如果你回到你的浏览器窗口,现在重新加载应用程序页面,你会注意到一个新的导航栏,每次你有超过4个链接在一般列表或任何单独的链接列表页面。

Updated application Landing Laravel with content pagination

有了功能页面化,您可以扩展您的内容,同时确保旧项目仍然可供用户和搜索引擎访问. 在您只需要基于某些标准的固定数量的结果的情况下,如果页面化不必要,您可以使用limit()方法来简化查询并保证有限的结果集。

Published At
Categories with 技术
comments powered by Disqus