Глобальные
Глобальные действия работают вне контекста конкретного ресурса. Они доступны:
- Программно — из любого места приложения через метод
dispatch() - Через Slim — в глобальном поиске, пользователь находит и запускает действие
Регистрация
Глобальные действия регистрируются в сервис-провайдере через Frame::registerGlobalActions():
use Frame\Core\Frame;
use App\Frame\Actions\SyncPricesAction;
use App\Frame\Actions\ClearCacheAction;
public function boot(): void
{
parent::boot();
Frame::registerGlobalActions([
SyncPricesAction::class,
ClearCacheAction::class,
]);
}
Можно передавать класс (будет разрешён через контейнер), экземпляр или callable:
Frame::registerGlobalActions([
// Класс — разрешается через app()
SyncPricesAction::class,
// Экземпляр
Action::make('Очистить кэш', 'Удалить все закэшированные данные')
->icon('tabler-trash')
->action(fn () => Artisan::call('cache:clear')
? Action::message('Кэш очищен')
: Action::error('Ошибка')),
]);
Создание класса действия
Глобальное действие — обычный класс Action. Отличие от ресурсных: метод handle() получает пустую коллекцию моделей.
class SyncPricesAction extends Action
{
public ?string $title = 'Синхронизировать цены';
public ?string $description = 'Запустить синхронизацию цен из внешнего API';
public ?string $icon = 'tabler-refresh';
public bool $confirmed = true;
public function fields(): array
{
return [
Select::make('currency', 'Валюта')
->options(['USD' => 'USD', 'EUR' => 'EUR', 'RUB' => 'RUB'])
->rules('required'),
];
}
public function handle(LazyCollection $models, ActionFields $fields): ?ActionResult
{
$count = PriceSync::run($fields->get('currency'));
return static::message("Синхронизировано {$count} цен");
}
}
Многошаговые действия (мастер)
Форму действия можно разбить на шаги — они отображаются как мастер (wizard). Объявите в классе метод steps(), возвращающий список шагов; каждый шаг — массив ['label' => ..., 'fields' => [...], 'description' => ...] (description опционально). Отдельный fields() при этом не нужен: поля собираются со всех шагов, валидация тоже общая.
class OnboardUserAction extends Action
{
public ?string $title = 'Онбординг';
public function steps(): array
{
return [
[
'label' => 'Профиль',
'fields' => [
Text::make('name', 'Имя')->required(),
],
],
[
'label' => 'Доступ',
'description' => 'Учётные данные',
'fields' => [
Text::make('email', 'Email')->required(),
Password::make('password', 'Пароль'),
],
],
];
}
public function handle(LazyCollection $models, ActionFields $fields): ?ActionResult
{
return static::message('Пользователь создан: ' . $fields->get('name'));
}
}
Step нет. Поддерживаются ключи label, fields и опциональный description; условий видимости на уровне шага нет.Программный вызов
Метод dispatch() позволяет выполнить действие из кода, минуя HTTP-слой:
// Без параметров
SyncPricesAction::make()->dispatch();
// С полями
SyncPricesAction::make()->dispatch(['currency' => 'USD']);
// С моделями
PublishAction::make()->dispatch(
fields: ['notify' => true],
models: Post::where('draft', true)->lazy(),
);
dispatch() оборачивает выполнение в транзакцию и записывает событие в журнал.
Отображение в Slim
Зарегистрированные глобальные действия автоматически появляются в секции «Действия» поиска Slim. Поддерживается:

- Нечёткий поиск по названию
- Авторизация — действие видно только пользователям с правами (через
->can()) - Подтверждение — модальное окно с кнопками подтверждения/отмены
- Поля формы — если действие определяет
fields(), они отображаются в модальном окне - Валидация — ошибки 422 показываются без закрытия модального окна
Авторизация
Ограничение доступа работает через метод can():
Frame::registerGlobalActions([
SyncPricesAction::make()->can('admin'),
Action::make('Опасное действие')
->can(fn (FrameRequest $request) => $request->user()->isOwner()),
]);
Действия, не прошедшие проверку, не отображаются в Slim и возвращают 403 при попытке вызова.
Деструктивные действия
Для опасных операций используйте DestructiveAction:
class PurgeDataAction extends DestructiveAction
{
public ?string $title = 'Очистить данные';
// ...
}
Деструктивные действия всегда требуют подтверждения и отображаются с красной кнопкой.
Именование
Глобальные действия автоматически получают имя вида global::slug-from-title. Например, действие с $title = 'Sync Prices' будет иметь имя global::sync-prices.
Результаты
Глобальные действия поддерживают все стандартные результаты:
return static::message('Операция выполнена');
return static::error('Что-то пошло не так');
return static::redirect('/reports/latest');
return static::push(['name' => 'dashboards', 'params' => ['name' => 'main']]);