如何在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()
方法,该方法会生成带有 previous 和 next 链接的基本导航。 与 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()
方法来简化查询并保证有限的结果集。