Laravel Nova 是一款 Laravel 应用程序的后台管理面板。当然,Nova 的主要功能是使用 Eloquent 管理底层数据库记录。Nova 通过在应用中定义一个与 Eloquent 模型对应的 Nova「资源」实现此目标。
Nova 资源默认存储在应用的 app/Nova 文件夹。你可以使用 nova:resource Artisan 命令生成一个新资源:
php artisan nova:resource Post资源的基本属性是 model 属性。此属性告诉 Nova 该资源对应的 Eloquent 模型:
/**
* 资源对应的模型。
*
* @var string
*/
public static $model = 'App\Models\Post';新创建的 Nova 资源只包含一个 ID 字段定义。别担心,我们很快会为我们的资源添加更多字段。
保留的资源名称
Nova 包含一些可能不用于资源名称的保留字:
自动注册
默认情况下,app/Nova 目录的所有资源由 Nova 自动注册。你无需手动注册它们。
资源在 Nova 管理面板中使用之前,必须先由 Nova 注册。资源一般在 app/Providers/NovaServiceProvider.php 文件里注册。该文件包含与 Nova 安装相关的各种配置和引导代码。
如上所述,你无需手动注册资源;但是,如果你选择手动注册,可以通过覆盖 NovaServiceProvider 的 resources 方法实现 。
手动注册资源有两种方法。可以使用 resourcesIn 方法指示 Nova 注册给定目录中所有的 Nova 资源。或者,也可以使用 resources 方法手动注册单个(或几个)资源:
use App\Nova\User;
use App\Nova\Post;
/**
* 注册应用程序的 Nova 资源。
*
* @return void
*/
protected function resources()
{
Nova::resourcesIn(app_path('Nova'));
Nova::resources([
User::class,
Post::class,
]);
}一旦你的资源用 Nova 注册完毕,它们将在 Nova 面板的侧栏中可用:

如果你不希望资源出现在侧边栏中,可以覆盖资源类的 displayInNavigation 属性:
/**
* 指示资源是否应显示在侧边栏中。
*
* @var bool
*/
public static $displayInNavigation = false;你可以通过在资源类上定义 menu 方法来自定义资源的菜单:
use Illuminate\Http\Request;
/**
* 获取资源的自定义菜单。
*
* @param \Illuminate\Http\Request $request
* @return \Laravel\Nova\Menu\MenuItem
*/
public function menu(Request $request)
{
return parent::menu($request)->withBadge(function () {
return static::$model::count();
});
}要了解更多信息, 请查看文档 自定义菜单 。
如果你想将资源分为不同的侧边栏组,可以覆盖资源类的 group 属性:
/**
* 与资源关联的逻辑组。
*
* @var string
*/
public static $group = 'Admin';Nova 支持为你的资源提供一些可视化定制选项。
有时,在资源索引表上显示更多数据很方便。为了实现这一点,可以使用 "tight" 表格样式选项,该选项旨在增加表格行的视觉密度。要完成此操作,请重写资源类上的静态 $tableStyle 属性或静态 tableStyle 方法:
/**
* 用于表格的视觉样式。可用选项有 'tight' and 'default'。(tight 是紧缩模式,缩小表格间距)
*
* @var string
*/
public static $tableStyle = 'tight';这将以较小的视觉高度显示表行,从而可以显示更多数据:

你可以配置 Nova 通过重写资源类上的静态 $showColumnBorders 属性或静态 showColumnBorders 方法来显示列边框:
/**
* 是否在显示每列的边框。
*
* @var bool
*/
public static $showColumnBorders = true;将此属性设置为 true 将会配置 Nova 在每个表项上显示带边框:

默认情况下,单击资源列表行时,Nova 将导航到资源的详细信息视图。但是,你可能希望 Nova 导航到编辑表单。你可以通过更改资源类的 clickAction 属性来自定义此行为:
/**
* 单击列表中的资源时要使用的单击操作。
*
* 可选项: 'detail' (default), 'edit', 'select', 'preview', or 'ignore'.
*
* @var string
*/
public static $clickAction = 'edit';选择 select 选项将选中资源行的复选框。ignore 选项指示 Nova 完全忽略单击事件。
如果你经常需要在字段、资源标题 或者 资源副标题 中访问资源关联,那么将此关联添加到资源的 with 属性里可能是个好主意。此属性指示 Nova 在检索资源时总是预加载列出的关联。
例如,如果你在一个 Post 资源的 subtitle 方法里访问此资源的 user 关联,你应该将 user 关联添加到 Post 资源的 with 属性里:
/**
* 在查询时应预加载的关联。
*
* @var array
*/
public static $with = ['user'];有时,你可能希望创建一个新资源,同时使用现有资源中的所有数据作为起点。Nova 的资源复制功能正是这样做的。单击复制按钮后,你将被带到一个资源创建表单,其中已复制资源的所有数据都已填充到该表单中,并准备进行调整:

要自定义复制模型,可以覆盖资源类上的 replicate 方法:
/**
* 返回一个已复制的资源。
*
* @return static
*
* @throws \InvalidArgumentException
*/
public function replicate()
{
return tap(parent::replicate(), function ($resource) {
$model = $resource->model();
$model->name = 'Duplicate of '.$model->name;
});
}附件可能无法复制
Markdown 和 Trix 字段如果使用了 withFiles 方法无法复制附件。
如果需要存储对原始资源ID的引用,则可以访问复制请求中的 fromResourceId 值。通常,此值将从正在侦听模型的 creating 事件的事件侦听器或观察者访问:
namespace App\Observers;
use App\Models\Post;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Nova;
class PostObserver
{
/**
* 处理新 Post 的创建。
*
* @param \App\Models\Post $model
* @return void
*/
public function creating(Post $model): void
{
Nova::whenServing(function (NovaRequest $request) use ($model) {
$model->parent_id = $request->input('fromResourceId');
});
}
}所有 Nova 操作都使用了你熟悉的 save, delete, forceDelete, restore 方法。因此,监听 Nova 触发的模型事件并作出响应非常容易。最简单的办法是直接给模型绑定一个 观察者 :
namespace App\Providers;
use App\Models\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* 启动所有应用服务。
*
* @return void
*/
public function boot()
{
parent::boot();
User::observe(UserObserver::class);
}
/**
* 注册此服务提供者。
*
* @return void
*/
public function register()
{
//
}
}如果你希望附加一个方法仅在 Nova 相关 HTTP 请求期间调用的观察者,则可以使用 Laravel\Nova\Observable 类提供的 make 方法注册观察者。通常,这应该在应用程序的 NovaServiceProvider 中完成:
use App\Models\User;
use Laravel\Nova\Observable;
use App\Observers\UserObserver;
/**
* 启动所有应用服务。
*
* @return void
*/
public function boot()
{
parent::boot();
Observable::make(User::class, UserObserver::class);
}或者,你可以使用 Nova 的 whenServing 方法来确定当前 HTTP 请求是否在 Observer 本身内为 Nova 相关请求提供服务:
namespace App\Observers;
use App\Models\User;
use Illuminate\Http\Request;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Nova;
class UserObserver
{
/**
* 处理用户 "created" 事件。
*
* @param \App\Models\User $user
* @return void
*/
public function created(User $user)
{
Nova::whenServing(function (NovaRequest $request) use ($user) {
// 仅在 Nova 请求期间调用...
}, function (Request $request) use ($user) {
// 为非 Nova 请求调用...
});
// 始终调用...
}
}Nova 还允许在资源上定义以下静态方法,以用作钩子,只有在从 Laravel Nova 中执行相应的资源操作时才会调用这些方法:
afterCreateafterUpdateafterDeleteafterForceDeleteafterRestore例如,你可能希望在 Nova 中创建用户后发送电子邮件验证通知:
use App\Models\User;
use App\Nova\Resource;
use Illuminate\Database\Eloquent\Model;
use Laravel\Nova\Http\Requests\NovaRequest;
class User extends Resource
{
/**
* 注册需要在创建资源后调用的回调。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public static function afterCreate(NovaRequest $request, Model $model)
{
$model->sendEmailVerificationNotification();
}
}如果模型自 Nova 上次检索以来已更新,Nova 将自动响应 409 Conflict HTTP 状态代码,并显示错误消息,以防止无意中更改模型。如果在你打开资源上的 「编辑」页面后,其他用户更新了模型,则可能会发生这种情况。这个功能也被称为 Nova "交通警察""。
如果你不关心防止冲突,可以通过将给定资源类的 trafficCop 属性设置为false 来禁用交通警察功能:
/**
* 指示 Nova 是否应在查看和更新资源之间检查修改是否冲突。
*
* @var bool
*/
public static $trafficCop = false;如果你有更强烈的自定义需求,也可以覆盖资源上的 trafficCop 方法,以确定是否应启用此功能:
/**
* 指示 Nova 是否应在查看和更新资源之间检查修改是否冲突。
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
public static function trafficCop(Request $request)
{
return static::$trafficCop;
}时间同步
如果你遇到交通警察问题,应确保使用 NTP 正确同步系统时间。
Nova 可以在指定的时间间隔自动获取资源的最新记录。要启用轮询,请覆盖资源类的 polling 属性:
/**
* 指示资源是否应自动轮询新资源。
*
* @var bool
*/
public static $polling = true;要自定义轮询间隔,可以用 Nova 在获取新资源记录之前应等待的秒数覆盖资源类上的 pollingInterval 属性:
/**
* Nova 轮询新资源的时间间隔。
*
* @var int
*/
public static $pollingInterval = 5;默认情况下,当启用资源轮询时,一旦页面加载,就无法禁用它。通过将资源类上的 showPollingToggle 属性设置为 true,你可以指示 Nova 显示资源轮询的 启动/ 停止 切换按钮:
/**
* 指示是否在 Nova 内部显示轮询切换按钮。
*
* @var bool
*/
public static $showPollingToggle = true;Nova 将显示一个可点击的按钮,你可以使用该按钮 启用 / 禁用 资源的轮询:

Nova 允许你轻松自定义用户在执行资源操作(如创建或更新资源)后重定向的位置:
Nova 的重定向功能使用 Inertia.js 的 visit 方法。因此,重定向仅限于 Laravel Nova 内的路径。你可以调用 URL::remote 方法重定向到外部 URL:
use Laravel\Nova\URL;
return URL::remote('https://nova.laravel.com');你可以通过重写资源的 redirectAfterCreate 方法,自定义用户在创建资源后重定向的位置:
/**
* 返回创建后重定向用户的位置。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Laravel\Nova\Resource $resource
* @return \Laravel\Nova\URL|string
*/
public static function redirectAfterCreate(NovaRequest $request, $resource)
{
return '/resources/'.static::uriKey().'/'.$resource->getKey();
}你可以通过重写资源的 redirectAfterUpdate 方法,自定义用户在更新资源后重定向的位置:
/**
* 返回更新后重定向用户的位置。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Laravel\Nova\Resource $resource
* @return \Laravel\Nova\URL|string
*/
public static function redirectAfterUpdate(NovaRequest $request, $resource)
{
return '/resources/'.static::uriKey().'/'.$resource->getKey();
}你可以通过重写资源的 redirectAfterDelete 方法,自定义用户在删除资源后重定向的位置:
/**
* 返回删除后重定向用户的位置。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return \Laravel\Nova\URL|string|null
*/
public static function redirectAfterDelete(NovaRequest $request)
{
return null;
}Nova 能够为你的资源列表显示分页链接。根据应用程序的需要,你可以在三种不同的样式之间进行选择:"simple", "load-more", 和 "links" :



默认情况下,Nova 资源使用 "simple" 样式显示。但是,你可以通过更改应用程序的 config/nova.php 配置文件中的 pagination 配置选项的值来自定义它,以使用 load-more 或 links 样式:
'pagination' => 'links',如果你想自定义每个资源的「每页」筛选菜单上显示的可选择的最大数量,可以通过自定义资源的 perPageOptions 属性来实现:
/**
* 为此资源配置的每页分页选项。
*
* @return array
*/
public static $perPageOptions = [50, 100, 150];或者,你可以覆盖应用程序的基本 Resource 类上的 perPageOptions 方法,该文件是在安装 Nova 时创建的:
/**
* 为此资源配置的每页分页选项。
*
* @return array
*/
public static function perPageOptions()
{
return [50, 100, 150];
}自定义 perPageOptions & 资源获取
更改 Resource 上的 perPageOptions 值将导致 Nova 获取的默认资源数量等于 perPageOptions 数组中的第一个值。
使用 $perPageViaRelationship 属性,你还可以自定义特定资源作为关联显示在另一个资源的详细视图上时所显示的资源数量:
/**
* 每页通过关联显示的资源数量。
*
* @var int
*/
public static $perPageViaRelationship = 10;有时,你可能需要将一组资源记录导出为 CSV 文件,以便与电子表格应用程序中的数据交互或将数据导入另一个系统。值得庆幸的是,Nova 内置了对导出资源数据的支持。
要开始使用本功能,请将 Laravel\Nova\Actions\ExportAsCsv 动作 添加到 Nova 资源中:
use Laravel\Nova\Actions\ExportAsCsv;
use Laravel\Nova\Http\Requests\NovaRequest;
/**
* 获取资源可用的动作。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function actions(NovaRequest $request)
{
return [
ExportAsCsv::make(),
];
}如果你希望允许用户命名下载的CSV文件,则可以在注册动作时调用 nameable 方法:
return [
ExportAsCsv::make()->nameable(),
];如果要自定义和格式化生成的 CSV 中包含的字段,则可以在注册动作时调用 withFormat 方法:
return [
ExportAsCsv::make()->withFormat(function ($model) {
return [
'ID' => $model->getKey(),
'Name' => $model->name,
'Email Address' => $model->email,
];
}),
];你可能希望自定义单个资源的索引列表的搜索所需时间。例如,为检索某些资源而执行的查询可能比其他查询花费更长的时间。你可以通过在资源类上设置 debounce 属性来自定义单个资源的搜索耗时:
/**
* 搜索此资源时要使用的时间好使(以秒为单位)。
*
* @var float
*/
public static $debounce = 0.5; // 0.5 seconds你可以按资源索引上的 C 键导航到 「创建资源」页面。在资源详细信息页面上,E 键可用于导航到「更新资源」页面。