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

来自菜鸟教程
跳转至:导航、​搜索

在本系列中,您一直在向演示应用程序添加新链接,以测试 Laravel Eloquent 的几个功能。 您可能已经注意到,每次添加新链接时,主索引页面都会变长,因为应用程序中显示的链接数量没有限制。 尽管当您拥有少量数据库条目时这不会成为问题,但从长远来看,这可能会导致您的页面加载时间更长,并且由于内容分布在单页。

在本系列的这一部分中,您将学习如何使用 limit() 方法限制 Laravel Eloquent 查询中的结果数量,以及如何使用 simplePaginate() 方法对结果进行分页。

限制查询结果

首先,您将更新主应用程序路由 (/) 以限制索引页面上列出的链接数量。

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

routes/web.php

然后,定位主路由定义:

路线/web.php

Route::get('/', function () {
    $links = Link::all()->sortDesc();
    return view('index', [
        'links' => $links,
        'lists' => LinkList::all()
    ]);
});

突出显示的行显示了通过 Link 模型 all() 方法获取数据库中当前所有链接的查询。 如本系列的前一部分所述,此方法继承自父 Model 类,并返回一个包含与该模型关联的所有数据库记录的集合。 sortDesc() 方法用于对生成的集合进行降序排序。

现在,您将更改突出显示的行以使用数据库查询排序方法 orderBy(),它在数据库级别对查询结果进行排序,而不是简单地重新排序通过 [ X242X] 方法。 您还将包含对 limit() 方法的链式调用,以限制查询结果。 最后,您将使用 get() 方法将过滤后的结果集作为 Eloquent 集合获得。

用以下代码替换您的主要路线。 为方便起见,突出显示了更改:

路线/web.php

Route::get('/', function () {
    $links = Link::orderBy('created_at', 'desc')->limit(4)->get();

    return view('index', [
        'links' => $links,
        'lists' => LinkList::all()
    ]);
});

更新后的代码现在将提取添加到数据库中的最新 4 个链接,无论在哪个列表中。 由于所有链接都添加到列表中,因此访问者仍然可以转到特定列表以查看完整的链接列表。

接下来,您将学习如何对结果进行分页,以确保所有链接仍然可以访问,即使它们不会在单个页面上一次全部加载。

分页查询结果

您的索引页面现在限制了列出的链接数量,这样您的页面就不会被内容超载,并且可以在更短的时间内呈现。 尽管此解决方案在许多情况下都可以正常工作,但您需要确保访问者仍然可以访问默认情况下不可见的旧链接。 最有效的方法是实现分页,用户可以在多页结果之间导航。

Laravel Eloquent 有本地方法来促进对数据库查询结果实现分页。 paginate()simplePaginate() 方法负责生成分页链接,处理 HTTP 参数以识别当前正在请求的页面,并使用正确的限制和偏移量查询数据库以获得预期的结果集,具体取决于您要列出的每页记录数。

您现在将更新 routes/web.php 中的 Eloquent 查询以使用 simplePaginate() 方法,该方法会生成带有 previousnext 链接的基本导航。 与 paginate() 方法不同,simplePaginate() 不显示查询结果中的总页数信息。

在代码编辑器中打开 routes/web.php 文件。 首先更新 / 路由,将 limit(4)->get() 方法调用替换为 simplePaginate() 方法:

路线/web.php

...
Route::get('/', function () {
    $links = Link::orderBy('created_at', 'desc')->simplePaginate(4);

    return view('index', [
        'links' => $links,
        'lists' => LinkList::all()
    ]);
});
...

接下来,在同一个文件中找到/{slug}路由定义,将get()方法替换为simplePaginate()方法。 这是完成后代码的外观:

路线/web.php

...
Route::get('/{slug}', function ($slug) {
    $list = LinkList::where('slug', $slug)->first();
    if (!$list) {
        abort(404);
    }

    return view('index', [
        'list' => $list,
        'links' => $list->links()->orderBy('created_at', 'desc')->simplePaginate(4),
        'lists' => LinkList::all()
    ]);
})->name('link-list');
...

这是完成后的 routes/web.php 文件的外观。 为方便起见,突出显示了这些更改:

路线/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Models\Link;
use App\Models\LinkList;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    $links = Link::orderBy('created_at', 'desc')->simplePaginate(4);

    return view('index', [
        'links' => $links,
        'lists' => LinkList::all()
    ]);
});

Route::get('/{slug}', function ($slug) {
    $list = LinkList::where('slug', $slug)->first();
    if (!$list) {
        abort(404);
    }

    return view('index', [
        'list' => $list,
        'links' => $list->links()->orderBy('created_at', 'desc')->simplePaginate(4),
        'lists' => LinkList::all()
    ]);
})->name('link-list');

完成后保存文件。

数据库查询现已更新,但您仍需要更新前端视图以包含将呈现导航栏的代码。 使用 simplePaginate() 获得的 Eloquent 集合包含一个名为 links() 的方法,可以从前端视图调用该方法以输出必要的 HTML 代码,该代码将基于分页的 Eloquent 查询呈现导航部分.

你也可以在分页的 Eloquent 集合中使用 links() 方法来访问固有的分页器对象,它提供了几个 有用的方法 来获取当前页面以及是否有内容等信息多页内容与否。

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

resources/views/index.blade.php

找到标有 links 类的部分的末尾,其中包含呈现链接的 foreach 循环。 在该部分之后和该页面上的最终 </div> 标记之前放置以下代码:

资源/视图/index.blade.php

        @if ($links->links()->paginator->hasPages())
            <div class="mt-4 p-4 box has-text-centered">
                {{ $links->links() }}
            </div>
        @endif

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

完成后,更新后的 index.blade.php 页面如下所示:

资源/视图/index.blade.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>My Awesome Links</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">

    <style>
        html {
            background: url("https://i.imgur.com/BWIdYTM.jpeg") no-repeat center center fixed;
            -webkit-background-size: cover;
            -moz-background-size: cover;
            -o-background-size: cover;
            background-size: cover;
        }

        div.link h3 {
            font-size: large;
        }

        div.link p {
            font-size: small;
            color: #718096;
        }
    </style>
</head>
<body>
<section class="section">
    <div class="container">
        <h1 class="title">
            @if (isset($list))
                {{ $list->title }}
            @else
                Check out my awesome links
            @endif
        </h1>
        <p class="subtitle">
            @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
        </p>

        <section class="links">
            @foreach ($links as $link)
                <div class="box link">
                    <h3><a href="{{ $link->url }}" target="_blank" title="Visit Link: {{ $link->url }}">{{ $link->description }}</a></h3>
                    <p>{{$link->url}}</p>
                    <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>
                </div>
            @endforeach
        </section>

        @if ($links->links()->paginator->hasPages())
            <div class="mt-4 p-4 box has-text-centered">
                {{ $links->links() }}
            </div>
        @endif
    </div>
</section>
</body>
</html>

完成更新后保存文件。 如果您现在返回浏览器窗口并重新加载应用程序页面,只要您在一般列表或任何单个链接列表页面中有超过 4 个链接,您就会注意到一个新的导航栏。

有了功能性分页,您可以增加内容,同时确保用户和搜索引擎仍然可以访问旧项目。 如果您只需要基于特定条件的固定数量的结果,而无需分页,您可以使用 limit() 方法来简化查询并保证有限的结果集。