Nova lenses 与过滤器类似,允许您完全自定义 Eloquent 的基础资源查询。例如,您可能希望按照终身总收入排序,列出应用程序的所有用户:

创建这样一个列表可能需要连接到其他表,并在查询中执行聚合函数。如果听起来很复杂,不用担心--镜头正是用来解决这种情况的。
要创建镜头,可以使用 nova:lens Artisan 命令。默认情况下,Nova 会将新生成的镜头放在 app/Nova/Lenses 目录中:
php artisan nova:lens MostValuableUsersNova 生成的每个镜头都包含多个方法。不过,我们目前关注的两个方法是 query 和 fields 方法。query 方法负责构建检索所需数据所需的 Eloquent 查询,而 fields 方法则返回查看镜头时应显示的字段数组。
要了解更多信息,让我们来看看显示用户及其终生收入的完整镜头定义。正如您在下面的示例中看到的,query 方法将利用 LensRequest 提供的 withFilters 和 withOrdering 方法,以指示 Nova 将任何选定的筛选器和排序约束也应用到查询中:
<?php
namespace App\Nova\Lenses;
use Illuminate\Support\Facades\DB;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Number;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\LensRequest;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Lenses\Lens;
class MostValuableUsers extends Lens
{
/**
* 获取镜头的查询生成器/分页器。
*
* @param \Laravel\Nova\Http\Requests\LensRequest $request
* @param \Illuminate\Database\Eloquent\Builder $query
* @return mixed
*/
public static function query(LensRequest $request, $query)
{
return $request->withOrdering($request->withFilters(
$query->select(self::columns())
->join('licenses', 'users.id', '=', 'licenses.user_id')
->groupBy('users.id', 'users.name')
->withCasts([
'revenue' => 'float',
])
), fn ($query) => $query->orderBy('revenue', 'desc'));
}
/**
* 获取应选择的字段。
*
* @return array
*/
protected static function columns()
{
return [
'users.id',
'users.name',
DB::raw('sum(licenses.price) as revenue'),
];
}
/**
* 获取镜头可用的字段。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function fields(NovaRequest $request)
{
return [
ID::make('ID', 'id'),
Text::make('Name', 'name'),
Number::make('Revenue', 'revenue', function ($value) {
return '$'.number_format($value, 2);
}),
];
}
/**
* 获取可用于镜头的卡片。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function cards(NovaRequest $request)
{
return [];
}
/**
* 获取适用于镜头的过滤器。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function filters(NovaRequest $request)
{
return [];
}
/**
* 获取镜头的可用动作。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function actions(NovaRequest $request)
{
return [];
}
/**
* 获取镜头的 URI key。
*
* @return string
*/
public function uriKey()
{
return 'most-profitable-users';
}
}如上例所示,query 方法可完全控制用于检索镜头数据的 Eloquent 查询。fields 方法可利用 Nova 的任何字段,以便适当显示查询检索到的数据。
列方法
在本例中,columns 方法是从 query 方法中提取出来的,以便于阅读。它不是 "必需 "的,也不是镜头的 "特征"。
镜头列选择
在编写镜头查询时,应尽量将资源的 ID 作为选定列。如果不包含 ID,Nova 将无法显示镜头的 「选择所有匹配」选项。此外,资源删除菜单也将不可用。
withOrdering 和 withFilters 方法用于为镜头查询应用排序和过滤器,应始终在 query 方法中应用。这两种方法都接受 $query 作为第一个参数,而 withOrdering 方法则接受一个闭包作为第二个参数。传递给 withOrdering 方法的闭包应为查询应用默认排序,如果没有从 Nova 面板选择其他排序,则会应用默认排序:
return $request->withOrdering(
$request->withFilters($query),
fn ($query) => $query->latest()
);Nova 可以通过轮询以指定的时间间隔自动获取镜头的最新记录。要启用轮询,请覆盖镜头类的 polling 属性:
/**
* 表示镜头是否应自动轮询新记录。
*
* @var bool
*/
public static $polling = true;要自定义轮询间隔,你可以覆盖镜头类上的 pollingInterval 属性。pollingInterval 定义了 Nova 在获取新记录前应等待的秒数:
/**
* Nova 轮询新镜头的时间间隔(秒)。
*
* @var int
*/
public static $pollingInterval = 5;默认情况下,当启用镜头轮询时,页面加载后无法禁用轮询。不过,你可以在镜头类中定义一个 showPollingToggle 属性为 true,指示 Nova 显示开始/停止轮询切换按钮:
/**
* 表示是否在 Nova 内部显示轮询切换按钮
*
* @var bool
*/
public static $showPollingToggle = true;每个 Nova 镜头还包含一个 filters 方法。该方法允许你将任何现有的 过滤器)附加到镜头上:
use App\Nova\Filters\UserType;
/**
* 获取适用于镜头的过滤器。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function filters(NovaRequest $request)
{
return [new UserType];
}每个 Nova 镜头还包含一个 actions 方法。该方法允许你将任何现有的 动作附加到镜头:
use App\Nova\Actions\Export;
/**
* 获取镜头的可用动作。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function actions(NovaRequest $request)
{
return [new Export];
}资源动作
默认情况下,镜头将继承其关联资源的操作。不过你可以覆盖镜头上的 actions 方法,以定义镜头可用的自定义动作集。
每个 Nova 镜头还包含一个 cards 方法。该方法允许你将任何现有的 指标 附加到镜头:
use App\Nova\Metrics\NewUsers;
/**
* 获取可用于镜头的卡片。
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @return array
*/
public function cards(NovaRequest $request)
{
return [new NewUsers];
}