简介

Laravel Folio 是一个功能强大的基于页面的路由器,旨在简化 Laravel 应用中的路由操作。使用 Laravel Folio,创建路由就如同在应用的 resources/views/pages 目录中创建一个 Blade 模板一样轻松。

例如,要创建一个可通过 /greeting URL 访问的页面,只需在应用的 resources/views/pages 目录中创建一个 greeting.blade.php 文件:

<div>
    Hello World
</div>

安装

开始使用前,通过 Composer 包管理器将 Folio 安装到你的项目中:

composer require laravel/folio

安装 Folio 后,你可以执行 folio:install Artisan 命令,该命令会将 Folio 的服务提供者安装到你的应用程序中。此服务提供者会注册 Folio 将要搜索路由/页面的目录:

php artisan folio:install

页面路径 / URI

默认情况下,Folio 从应用的 resources/views/pages 目录提供页面,但你可以在 Folio 服务提供者的 boot 方法中自定义这些目录。

例如,有时在同一个 Laravel 应用中指定多个 Folio 路径可能会很方便。你可能希望为应用的“管理”区域单独设置一个 Folio 页面目录,同时为应用的其他页面使用另一个目录。

你可以使用 Folio::path 和 Folio::uri 方法来实现这一点。path 方法注册一个目录,Folio 在路由传入的 HTTP 请求时会扫描该目录中的页面,而 uri 方法则指定该页面目录的“基础 URI”:

use Laravel\Folio\Folio;

Folio::path(resource_path('views/pages/guest'))->uri('/');

Folio::path(resource_path('views/pages/admin'))
    ->uri('/admin')
    ->middleware([
        '*' => [
            'auth',
            'verified',

            // ...
        ],
    ]);

子域名路由

你还可以根据传入请求的子域名将请求路由到页面。例如,你可能希望将来自 admin.example.com 的请求路由到与其余 Folio 页面不同的页面目录。你可以通过在调用 Folio::path 方法后调用 domain 方法来实现这一点:

use Laravel\Folio\Folio;

Folio::domain('admin.example.com')
    ->path(resource_path('views/pages/admin'));

domain 方法还允许你将域名或子域名的部分捕获为参数。这些参数将被注入到你的页面模板中:

use Laravel\Folio\Folio;

Folio::domain('{account}.example.com')
    ->path(resource_path('views/pages/admin'));

创建路由

你可以将 Blade 模板放置在任何一个 Folio 挂载的目录中来创建 Folio 路由。默认情况下,Folio 挂载 resources/views/pages 目录,但你可以在 Folio 服务提供者的 boot 方法中自定义这些目录。

一旦将 Blade 模板放置在 Folio 挂载的目录中,你就可以立即通过浏览器访问它。例如,放置在 pages/schedule.blade.php 中的页面可以在浏览器中通过 http://example.com/schedule 进行访问。

要快速查看所有 Folio 页面 / 路由的列表,你可以调用 folio:list Artisan 命令:

php artisan folio:list

嵌套路由

你可以在 Folio 的某个目录中创建一个或多个子目录来创建嵌套路由。例如,要创建一个可通过 /user/profile 访问的页面,可以在 pages/user 目录中创建一个 profile.blade.php 模板:

php artisan folio:page user/profile

# pages/user/profile.blade.php → /user/profile

索引路由

有时,你可能希望将某个页面设为目录的“索引”。通过在 Folio 目录中放置一个 index.blade.php 模板,对该目录根路径的任何请求都将被路由到该页面:

php artisan folio:page index
# pages/index.blade.php → /

php artisan folio:page users/index
# pages/users/index.blade.php → /users

路由参数

通常,你需要将传入请求 URL 中的片段注入到页面中,以便与之交互。例如,你可能需要访问正在显示的个人资料对应的用户“ID”。要实现这一点,你可以用方括号将页面文件名中的某个片段括起来:

php artisan folio:page "users/[id]"

# pages/users/[id].blade.php → /users/1

捕获的片段可以在 Blade 模板中作为变量访问:

<div>
    User {{ $id }}
</div>

要捕获多个片段,可以在括起来的片段前添加三个点 ...:

php artisan folio:page "users/[...ids]"

# pages/users/[...ids].blade.php → /users/1/2/3

当捕获多个片段时,捕获的片段将以数组的形式注入到页面中:

<ul>
    @foreach ($ids as $id)
        <li>User {{ $id }}</li>
    @endforeach
</ul>

路由模型绑定

如果页面模板文件名中的通配符片段与应用中的某个 Eloquent 模型对应,Folio 将自动利用 Laravel 的路由模型绑定功能,并尝试将解析出的模型实例注入到你的页面中:

php artisan folio:page "users/[User]"

# pages/users/[User].blade.php → /users/1

捕获的模型可以在 Blade 模板中作为变量访问。模型的变量名将转换为“驼峰命名法”:

<div>
    User {{ $user->id }}
</div>

自定义键

有时你可能希望使用除 id 之外的列来解析绑定的 Eloquent 模型。为此,你可以在页面的文件名中指定该列。例如,文件名为 [Post:slug].blade.php 的页面会尝试通过 slug 列而非 id 列来解析绑定的模型。

在 Windows 系统中,应使用 - 分隔模型名和键:[Post-slug].blade.php。

模型位置

默认情况下,Folio 会在应用的 app/Models 目录中搜索模型。不过,如有需要,你可以在模板的文件名中指定完全限定的模型类名:

php artisan folio:page "users/[.App.Models.User]"

# pages/users/[.App.Models.User].blade.php → /users/1

软删除模型

默认情况下,在解析隐式模型绑定时,不会检索已被软删除的模型。不过,如果你希望如此,可以通过在页面模板中调用 withTrashed 函数,指示 Folio 检索软删除的模型:

<?php

use function Laravel\Folio\{withTrashed};

withTrashed();

?>

<div>
    User {{ $user->id }}
</div>

渲染钩子

默认情况下,Folio 会将页面 Blade 模板的内容作为对传入请求的响应返回。不过,你可以通过在页面模板中调用 render 函数来自定义响应。

render 函数接受一个闭包,该闭包会接收 Folio 正在渲染的 View 实例,允许你向视图添加额外数据或自定义整个响应。除了接收 View 实例外,任何额外的路由参数或模型绑定也会提供给 render 闭包:

<?php

use App\Models\Post;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;

use function Laravel\Folio\render;

render(function (View $view, Post $post) {
    if (! Auth::user()->can('view', $post)) {
        return response('Unauthorized', 403);
    }

    return $view->with('photos', $post->author->photos);
}); ?>

<div>
    {{ $post->content }}
</div>

<div>
    This author has also taken {{ count($photos) }} photos.
</div>

命名路由

你可以使用 name 函数为某个页面的路由指定名称:

<?php

use function Laravel\Folio\name;

name('users.index');

就像 Laravel 的命名路由一样,你可以使用 route 函数为已分配名称的 Folio 页面生成 URL:

<a href="{{ route('users.index') }}">
    All Users
</a>

如果页面有参数,你可以简单地将它们的值传递给 route 函数:

route('users.show', ['user' => $user]);

中间件

你可以通过在页面模板中调用 middleware 函数,为特定页面应用中间件:

<?php

use function Laravel\Folio\{middleware};

middleware(['auth', 'verified']);

?>

<div>
    Dashboard
</div>

或者,若想为一组页面分配中间件,可在调用 Folio::path 方法后链式调用 middleware 方法。

若要指定中间件应应用到哪些页面,可使用这些页面对应的 URL 模式作为键来索引中间件数组。* 字符可用作通配符:

use Laravel\Folio\Folio;

Folio::path(resource_path('views/pages'))->middleware([
    'admin/*' => [
        'auth',
        'verified',

        // ...
    ],
]);

您可以在中间件数组中包含闭包,以定义内联的匿名中间件:

use Closure;
use Illuminate\Http\Request;
use Laravel\Folio\Folio;

Folio::path(resource_path('views/pages'))->middleware([
    'admin/*' => [
        'auth',
        'verified',

        function (Request $request, Closure $next) {
            // ...

            return $next($request);
        },
    ],
]);

路由缓存

使用 Folio 时,您应始终充分利用Laravel 的路由缓存功能。Folio 会监听 route:cache Artisan 命令,以确保 Folio 页面定义和路由名称得到正确缓存,从而获得最佳性能。