logo

定义操作

Nova 操作允许您对一个或多个 Eloquent 模型执行自定义任务。例如,您可以编写一个操作,向用户发送包含他们请求的帐户数据的电子邮件。或者,您可以编写一个操作将一组记录转移到另一个用户。

将操作附加到资源定义后,您可以从资源的索引或详细信息页面启动它。

Action

如果为资源的表格行启用了操作显示,您也可以从资源的索引页面通过资源的操作下拉菜单启动操作。这些操作被称为“内联操作”。

Inline Action

概述

Nova 操作可以使用 nova:action Artisan 命令生成。默认情况下,所有操作都放置在 app/Nova/Actions 目录中。

bash
php artisan nova:action EmailAccountProfile

您可以通过传递 --destructive 选项来生成 破坏性操作

bash
php artisan nova:action DeleteUserData --destructive

要了解如何定义 Nova 操作,让我们看一个例子。在这个例子中,我们将定义一个操作,向用户或用户组发送电子邮件。

php
<?php

namespace App\Nova\Actions;

use App\Models\AccountData;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Collection;
use Laravel\Nova\Actions\Action;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Fields\ActionFields;

class EmailAccountProfile extends Action
{
    use InteractsWithQueue, Queueable;

    /**
    * Perform the action on the given models.
    *
    * @param  \Laravel\Nova\Fields\ActionFields  $fields
    * @param  \Illuminate\Support\Collection  $models
    * @return mixed
    */
    public function handle(ActionFields $fields, Collection $models)
    {
        foreach ($models as $model) {
            (new AccountData($model))->send();
        }
    }

    /**
    * Get the fields available on the action.
    *
    * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
    * @return array
    */
    public function fields(NovaRequest $request)
    {
        return [];
    }
}

操作最重要的方法是 handle 方法。handle 方法接收附加到操作的任何字段的值,以及选定模型的集合。handle 方法**始终**接收一个 Collection 模型,即使操作仅针对单个模型执行。

handle 方法中,您可以执行完成操作所需的任何任务。您可以自由更新数据库记录、发送电子邮件、调用其他服务等。一切皆有可能!

操作标题

通常,Nova 使用操作的类名来确定应在操作选择菜单中显示的操作的显示名称。如果您想更改操作的显示名称,可以在操作类上定义一个 name 属性。

php
/**
 * The displayable name of the action.
 *
 * @var string
 */
public $name = 'Action Title';

破坏性操作

您可以通过定义扩展 Laravel\Nova\Actions\DestructiveAction 的操作类来将操作指定为破坏性或危险操作。这将更改操作确认按钮的颜色为红色。

Destructive Action

破坏性操作和策略

当将破坏性操作添加到具有关联授权策略的资源时,策略的 delete 方法必须返回 true,才能使操作运行。

操作回调

排队操作回调

如果您的操作已排队,则不应使用 Action::then 方法。要使用排队操作实现类似的功能,您应该利用 Nova 的 操作批处理回调

当对多个资源运行操作时,您可能希望在操作完成对所有资源的执行后执行一些代码。例如,您可能希望生成一份报告,详细说明所有选定资源的更改。要实现这一点,您可以在 注册操作 时调用 then 方法。

then 方法接受一个闭包,该闭包将在操作完成对所有选定资源的执行后被调用。闭包将接收一个扁平化的 Laravel 集合,其中包含操作返回的值。

例如,请注意以下操作的 handle 方法返回它接收的 $models

php
public function handle(ActionFields $fields, Collection $models)
{
    foreach ($models as $model) {
        (new AccountData($model))->send();
    }

    return $models;
}

在资源上注册此操作时,我们可以使用 then 回调来访问返回的模型并在操作完成执行后与它们进行交互。

php
public function actions(NovaRequest $request)
{
    return [
        (new Actions\EmailAccountProfile)->then(function ($models) {
            $models->each(function ($model) {
                //
            });
        }),
    ];
}

操作字段

有时您可能希望在调度操作之前从用户那里收集更多信息。为此,Nova 允许您将大多数 Nova 支持的 字段 直接附加到操作。当操作启动时,Nova 会提示用户为这些字段提供输入。

Action Field

要向操作添加字段,请将字段添加到操作的 fields 方法返回的字段数组中。

php
use Laravel\Nova\Fields\Text;

/**
 * Get the fields available on the action.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function fields(NovaRequest $request)
{
    return [
        Text::make('Subject'),
    ];
}

最后,在操作的 handle 方法中,您可以使用提供的 ActionFields 实例上的动态访问器来访问您的字段。

php
/**
 * Perform the action on the given models.
 *
 * @param  \Laravel\Nova\Fields\ActionFields  $fields
 * @param  \Illuminate\Support\Collection  $models
 * @return mixed
 */
public function handle(ActionFields $fields, Collection $models)
{
    foreach ($models as $model) {
        (new AccountData($model))->send($fields->subject);
    }
}

操作字段默认值

您可以使用 default 方法为操作字段设置默认值。

php
Text::make('Subject')->default(function ($request) {
    return 'Test: Subject';
}),

操作响应

通常,当执行操作时,Nova UI 会显示通用的“成功”消息。但是,您可以使用 ActionResponse 类提供的多种方法自定义此响应。要显示自定义的“成功”消息,您可以在 handle 方法中调用 ActionResponse::message 方法。

php
use Laravel\Nova\Actions\ActionResponse;

/**
 * Perform the action on the given models.
 *
 * @param  \Laravel\Nova\Fields\ActionFields  $fields
 * @param  \Illuminate\Support\Collection  $models
 * @return mixed
 */
public function handle(ActionFields $fields, Collection $models)
{
    // ...

    return ActionResponse::message('It worked!');
}

要返回红色“危险”消息,您可以调用 ActionResponse::danger 方法。

php
use Laravel\Nova\Actions\ActionResponse;

return ActionResponse::danger('Something went wrong!');

重定向响应

要将用户重定向到操作执行后的全新位置,您可以使用 ActionResponse::redirect 方法。

php
use Laravel\Nova\Actions\ActionResponse;

return ActionResponse::redirect('https://example.com');

要将用户重定向到 Nova 中的另一个位置,您可以使用 ActionResponse::visit 方法。

php
use Laravel\Nova\Actions\ActionResponse;

return ActionResponse::visit('/resources/posts/new', [
    'viaResource' => 'users',
    'viaResourceId' => 1,
    'viaRelationship' => 'posts'
]);

要将用户重定向到新浏览器标签页中的新位置,您可以使用 ActionResponse::openInNewTab 方法。

php
use Laravel\Nova\Actions\ActionResponse;

return ActionResponse::openInNewTab('https://example.com');

下载响应

要操作执行后启动文件下载,您可以使用 ActionResponse::download 方法。download 方法接受所需的文件名作为第一个参数,并接受要下载的文件的 URL 作为第二个参数。

php
use Laravel\Nova\Actions\ActionResponse;

return ActionResponse::download('Invoice.pdf', 'https://example.com/invoice.pdf');

自定义模态响应

除了操作执行之前和期间提供的自定义选项外,Nova 还支持向用户呈现自定义模态响应。这使您可以根据您的用例向用户提供额外的上下文或后续操作。

例如,假设您定义了一个名为 GenerateApiToken 的操作,该操作创建用于 REST API 的唯一令牌。使用自定义操作响应模态,您可以向运行操作的用户显示一个模态,允许他们将新生成的 API 令牌复制到剪贴板。

使用 nova:asset Artisan 命令,您可以 生成自定义资产 并将自定义模态注册到 Nova 的 Vue 实例中。

js
import ApiTokenCopier from "./components/ApiTokenCopier";

Nova.booting(app => {
  app.component("api-token-copier", ApiTokenCopier);
});

接下来,您可以在操作的 handle 方法中使用 modal 方法,该方法将指示 Nova 在运行操作后显示模态,并将 Vue 组件的名称和您指定的所有其他数据传递给组件。这些数据将作为道具提供给自定义模态的 Vue 组件。

php
public function handle(ActionFields $fields, Collection $models)
{
    if ($models->count() > 1) {
        return Action::danger('Please run this on only one user resource.');
    }

    $models->first()->update(['api_token' => $token = Str::random(32)]);

    return Action::modal('api-token-copier', [
        'message' => 'The API token was generated!',
        'token' => $token,
    ]);
}

排队操作

有时,您可能有一些需要一段时间才能完成运行的操作。为此,Nova 使您能够轻松地 排队 您的操作。要指示 Nova 将操作排队而不是同步运行它,请使用 ShouldQueue 接口标记操作。

php
<?php

namespace App\Nova\Actions;

use App\Models\AccountData;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Collection;
use Laravel\Nova\Actions\Action;
use Laravel\Nova\Contacts\BatchableAction;
use Laravel\Nova\Fields\ActionFields;

class EmailAccountProfile extends Action implements ShouldQueue
{
    use InteractsWithQueue, Queueable;

    // ...
}

您可以通过在执行 nova:action Artisan 命令时提供 --queued 选项来快速创建排队的 Nova 操作。

bash
php artisan nova:action EmailAccountProfile --queued

使用排队操作时,请不要忘记为您的应用程序配置和启动 队列工作者。否则,您的操作将不会被处理。

排队操作文件

目前,Nova 不支持将 File 字段附加到排队操作。如果您需要将 File 字段附加到操作,则操作必须同步运行。

自定义连接和队列

您可以在操作的构造函数中设置 $connection$queue 属性,从而自定义操作排队的队列连接和队列名称。

php
/**
 * Create a new action instance.
 *
 * @return void
 */
public function __construct()
{
    $this->connection = 'redis';
    $this->queue = 'emails';
}

作业批处理

您还可以通过使用 Laravel\Nova\Contracts\BatchableAction 接口标记操作,来指示 Nova 将操作排队为 批处理。此外,操作应使用 Illuminate\Bus\Batchable 特性。

当操作可批处理时,您应该定义一个 withBatch 方法,该方法将负责配置操作的 批处理回调。这允许您定义在针对多个选定资源执行完一整批操作后应运行的代码。实际上,您甚至可以访问在执行批处理操作时选定的所有资源的模型 ID。

php
<?php

namespace App\Nova\Actions;

use App\Models\AccountData;
use Illuminate\Bus\Batch;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\PendingBatch;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Collection;
use Laravel\Nova\Actions\Action;
use Laravel\Nova\Contacts\BatchableAction;
use Laravel\Nova\Fields\ActionFields;
use Throwable;

class EmailAccountProfile extends Action implements BatchableAction, ShouldQueue
{
    use Batchable, InteractsWithQueue, Queueable;

    /**
     * Prepare the given batch for execution.
     *
     * @param  \Laravel\Nova\Fields\ActionFields  $fields
     * @param  \Illuminate\Bus\PendingBatch  $batch
     * @return void
     */
    public function withBatch(ActionFields $fields, PendingBatch $batch)
    {
        $batch->then(function (Batch $batch) {
            // All jobs completed successfully...

            $selectedModels = $batch->resourceIds;
        })->catch(function (Batch $batch, Throwable $e) {
            // First batch job failure detected...
        })->finally(function (Batch $batch) {
            // The batch has finished executing...
        });
    }
}

操作日志

查看针对特定资源运行的操作日志通常很有用。此外,在排队操作时,了解排队操作何时实际完成执行通常很重要。值得庆幸的是,Nova 通过将 Laravel\Nova\Actions\Actionable 特性附加到资源的相应 Eloquent 模型,使添加操作日志变得轻而易举。

例如,我们可以将 Laravel\Nova\Actions\Actionable 特性附加到 User Eloquent 模型。

php
<?php

namespace App;

use Laravel\Nova\Actions\Actionable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Actionable, Notifiable;

    // ...
}

将特性附加到模型后,Nova 将自动开始在资源的详细信息页面底部显示操作日志。

Action Log

禁用操作日志

如果您不想在操作日志中记录操作,可以在操作类中添加 withoutActionEvents 属性来禁用此行为。

php
/**
 * Disables action log events for this action.
 *
 * @var bool
 */
public $withoutActionEvents = true;

或者,使用 withoutActionEvents 方法,您可以在将操作附加到资源时禁用操作日志。当操作经常针对数千个资源执行时,禁用操作日志通常特别有用,因为它允许您避免数千个缓慢的、顺序的操作日志数据库插入。

php
/**
 * Get the actions available for the resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function actions(NovaRequest $request)
{
    return [
        (new SomeAction)->withoutActionEvents()
    ];
}

排队操作状态

在排队操作运行时,您可以通过其模型集合更新操作针对任何传递给操作的模型的“状态”。例如,您可以使用操作的 markAsFinished 方法来指示操作已完成处理特定模型。

php
/**
 * Perform the action on the given models.
 *
 * @param  \Laravel\Nova\Fields\ActionFields  $fields
 * @param  \Illuminate\Support\Collection  $models
 * @return mixed
 */
public function handle(ActionFields $fields, Collection $models)
{
    foreach ($models as $model) {
        (new AccountData($model))->send($fields->subject);

        $this->markAsFinished($model);
    }
}

或者,如果您想指示操作针对给定模型“失败”,可以使用 markAsFailed 方法。

php
/**
 * Perform the action on the given models.
 *
 * @param  \Laravel\Nova\Fields\ActionFields  $fields
 * @param  \Illuminate\Support\Collection  $models
 * @return mixed
 */
public function handle(ActionFields $fields, Collection $models)
{
    foreach ($models as $model) {
        try {
            (new AccountData($model))->send($fields->subject);
        } catch (Exception $e) {
            $this->markAsFailed($model, $e);
        }
    }
}

操作模态自定义

默认情况下,操作在运行之前会询问用户确认。您可以自定义确认消息、确认按钮和取消按钮,以便在运行操作之前为用户提供更多上下文。这可以通过在定义操作时调用 `confirmText`、`confirmButtonText` 和 `cancelButtonText` 方法来实现。

php
/**
 * Get the actions available for the resource.
 *
 * @param  \Laravel\Nova\Http\Requests\NovaRequest  $request
 * @return array
 */
public function actions(NovaRequest $request)
{
    return [
        (new Actions\ActivateUser)
            ->confirmText('Are you sure you want to activate this user?')
            ->confirmButtonText('Activate')
            ->cancelButtonText("Don't activate"),
    ];
}