Laravel Actions, Events & Jobs
Quando usar esta skill
Use esta skill sempre que:
- •Criar lógica de negócio para Laravel
- •Separar side-effects da lógica principal
- •Criar background jobs
- •Configurar model observers
- •Implementar event-driven architecture
Princípios Fundamentais
- •Actions over Services - Sempre use
lorisleiva/laravel-actions - •Event-Driven - Use Events + Listeners para side effects
- •Observers - Use para model lifecycle hooks
- •Jobs - Queue via Actions implementando
ShouldQueue
Criando Actions
bash
php artisan make:action CreateBusiness
Estrutura de Action
php
<?php
declare(strict_types=1);
namespace App\Actions\Business;
use App\DataObjects\Business\CreateBusinessData;
use App\Models\Business;
use App\Models\Tenant;
use Lorisleiva\Actions\Concerns\AsAction;
final class CreateBusinessAction
{
use AsAction;
/**
* Execute action.
*/
public function handle(Tenant $tenant, CreateBusinessData $data): Business
{
// Check limits
if (!$tenant->isWithinLimit('businesses')) {
throw new \Exception('Business limit exceeded');
}
// Create business
$business = $tenant->businesses()->create($data->toArray());
// Increment usage
$tenant->incrementUsage('businesses');
// Dispatch event
event(new BusinessCreated($business));
return $business;
}
/**
* Use as controller (optional).
*/
public function asController(StoreBusinessRequest $request): Business
{
$data = CreateBusinessData::fromRequest($request->validated());
return $this->handle(auth()->user()->tenant, $data);
}
/**
* Run as queued job (optional).
*/
public function asJob(Tenant $tenant, CreateBusinessData $data): void
{
$this->handle($tenant, $data);
}
}
Uso de Actions
php
// Run sincronamente
CreateBusinessAction::run($tenant, $data);
// Run em background (queued)
CreateBusinessAction::dispatch($tenant, $data);
// Run com delay
CreateBusinessAction::dispatch($tenant, $data)->delay(now()->addMinutes(5));
// Run em fila específica
CreateBusinessAction::dispatch($tenant, $data)->onQueue('high');
Value Objects (DTOs)
CRÍTICO: Actions DEVEM usar Value Objects - NUNCA passe arrays crusos.
Por Que Usar Value Objects?
✅ Type Safety - Detecta erros em tempo de compilação
✅ Suporte IDE - Autocompletion
✅ Validação Centralizada - Em um lugar
✅ Imutabilidade - Previne mutações
✅ Self-Documenting - Contrato claro
✅ Reusabilidade - Use across Actions/Jobs/Events
❌ Single primitive values
❌ Eloquent models
❌ Collections
Criando Value Objects
php
<?php
declare(strict_types=1);
namespace App\DataObjects\Business;
final readonly class CreateBusinessData
{
public function __construct(
public string $name,
public string $type,
public ?string $email = null,
public ?string $phone = null,
public ?array $settings = null,
) {}
public static function fromRequest(array $data): self
{
return new self(
name: $data['name'],
type: $data['type'],
email: $data['email'] ?? null,
phone: $data['phone'] ?? null,
settings: $data['settings'] ?? null,
);
}
public function toArray(): array
{
return [
'name' => $this->name,
'type' => $this->type,
'email' => $this->email,
'phone' => $this->phone,
'settings' => $this->settings ?? [],
];
}
}
Quando Usar Value Objects
✅ Action parameters (sempre para inputs complexos)
✅ Service methods
✅ API responses
✅ Event payloads
✅ Jobs data
❌ Single primitive values
❌ Eloquent models
❌ Collections
Events & Listeners
Event:
php
<?php
namespace App\Events;
use App\Models\Business;
use Illuminate\Foundation\Events\Dispatchable;
final class BusinessCreated
{
use Dispatchable;
public function __construct(public Business $business) {}
}
Listener (as Action):
php
<?php
namespace App\Listeners;
use App\Events\BusinessCreated;
use Lorisleiva\Actions\Concerns\AsAction;
final class SendBusinessWelcomeEmail
{
use AsAction;
public function handle(BusinessCreated $event): void
{
// Send welcome email
}
}
Model Observers
bash
php artisan make:observer BusinessObserver --model=Business
php
<?php
namespace App\Observers;
use App\Models\Business;
final class BusinessObserver
{
public function creating(Business $business): void
{
$business->slug = Str::slug($business->name);
}
public function created(Business $business): void
{
event(new BusinessCreated($business));
}
public function updating(Business $business): void
{
if ($business->isDirty('name')) {
$business->slug = Str::slug($business->name);
}
}
}
Registrar em AppServiceProvider:
php
public function boot(): void
{
Business::observe(BusinessObserver::class);
}
Melhores Práticas
✅ FAÇA
- •Use Actions para toda lógica de negócio
- •Use Value Objects para dados complexos
- •Use Events para side-effects
- •Use Observers para model lifecycle
- •Use Jobs para processos longos
- •Dispatch Events após mudanças de estado
- •Mantenha Actions focadas (single responsibility)
❌ NÃO FAÇA
- •Não crie Services tradicionais
- •Não passe arrays crusos para Actions
- •Não coloque lógica de negócio em Models
- •Não esqueça de usar Events
- •Não use DB facade em Actions
- •Não crie Actions sem tipagem
Referências Cruzadas
- •Estrutura Actions/DTOs: Veja
laravel-architecturepara estrutura completa de Actions e Value Objects - •Traduções: Veja
laravel-i18npara traduções de Events e mensagens de sistema - •Exceções: Veja
laravel-exceptionspara criar exceções customizadas em Actions - •Testes: Veja
laravel-testing-pestpara testes de Actions, Jobs e Events
Referências
- •
docs/07-actions-events-jobs.md- Documentação completa - •Laravel Actions Documentation - Documentação oficial
- •Laravel Events Documentation - Documentação Laravel