---
description: Crear Action para lógica de negocio reutilizable
---

# Crear Action

Este workflow crea un Action para encapsular lógica de negocio reutilizable.

## ¿Cuándo usar Actions?

- Lógica que se repite en múltiples lugares
- Operaciones complejas que involucran múltiples modelos
- Lógica que podría ser llamada desde controllers, jobs, commands
- Operaciones que requieren transacciones de base de datos

## Parámetros Requeridos

- `{Funcionalidad}`: Nombre de la funcionalidad (ej: Users, Orders, Payments)
- `{Verbo}`: Acción que realiza (Create, Update, Delete, Process, Send, etc.)
- `{Nombre}`: Nombre del recurso (ej: User, Order, Invoice)

## Pasos

### 1. Crear Action

// turbo

```bash
php artisan make:class Actions/{Funcionalidad}/{Verbo}{Nombre}Action --no-interaction
```

### 2. Implementar Action

Editar `app/Actions/{Funcionalidad}/{Verbo}{Nombre}Action.php`:

```php
<?php

declare(strict_types=1);

namespace App\Actions\{Funcionalidad};

use App\Models\{Nombre};

final class {Verbo}{Nombre}Action
{
    /**
     * Execute the action.
     */
    public function execute(array $data): {Nombre}
    {
        // Implementar lógica aquí
    }
}
```

### 3. Formatear Código

// turbo

```bash
vendor/bin/pint app/Actions/{Funcionalidad}/{Verbo}{Nombre}Action.php
```

## Ejemplos

### CreateUserAction

```php
<?php

declare(strict_types=1);

namespace App\Actions\Users;

use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

final class CreateUserAction
{
    /**
     * Execute the action.
     *
     * @param array{name: string, email: string, password: string, role?: string} $data
     */
    public function execute(array $data): User
    {
        return DB::transaction(function () use ($data) {
            $user = User::create([
                'name' => $data['name'],
                'email' => $data['email'],
                'password' => Hash::make($data['password']),
            ]);

            if (isset($data['role'])) {
                $user->assignRole($data['role']);
            }

            return $user;
        });
    }
}
```

### UpdateUserAction

```php
<?php

declare(strict_types=1);

namespace App\Actions\Users;

use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

final class UpdateUserAction
{
    /**
     * Execute the action.
     *
     * @param array{name?: string, email?: string, password?: string, role?: string} $data
     */
    public function execute(User $user, array $data): User
    {
        return DB::transaction(function () use ($user, $data) {
            $updateData = collect($data)
                ->only(['name', 'email'])
                ->toArray();

            if (isset($data['password'])) {
                $updateData['password'] = Hash::make($data['password']);
            }

            $user->update($updateData);

            if (isset($data['role'])) {
                $user->syncRoles([$data['role']]);
            }

            return $user->fresh();
        });
    }
}
```

### DeleteUserAction

```php
<?php

declare(strict_types=1);

namespace App\Actions\Users;

use App\Models\User;
use Illuminate\Support\Facades\DB;

final class DeleteUserAction
{
    /**
     * Execute the action.
     */
    public function execute(User $user): bool
    {
        return DB::transaction(function () use ($user) {
            // Soft delete relacionados
            $user->posts()->delete();
            $user->comments()->delete();

            return $user->delete();
        });
    }
}
```

### ProcessOrderAction (Complejo)

```php
<?php

declare(strict_types=1);

namespace App\Actions\Orders;

use App\Models\Order;
use App\Services\PaymentService;
use App\Services\InventoryService;
use App\Services\NotificationService;
use Illuminate\Support\Facades\DB;

final class ProcessOrderAction
{
    public function __construct(
        private PaymentService $paymentService,
        private InventoryService $inventoryService,
        private NotificationService $notificationService,
    ) {}

    /**
     * Execute the action.
     *
     * @throws \App\Exceptions\PaymentFailedException
     * @throws \App\Exceptions\InsufficientInventoryException
     */
    public function execute(Order $order): Order
    {
        return DB::transaction(function () use ($order) {
            // Verificar inventario
            $this->inventoryService->reserve($order->items);

            // Procesar pago
            $payment = $this->paymentService->charge(
                $order->user,
                $order->total
            );

            // Actualizar orden
            $order->update([
                'status' => 'processing',
                'payment_id' => $payment->id,
                'processed_at' => now(),
            ]);

            // Reducir inventario
            $this->inventoryService->reduce($order->items);

            // Notificar al usuario
            $this->notificationService->orderConfirmed($order);

            return $order->fresh();
        });
    }
}
```

## Uso en Controllers

```php
<?php

namespace App\Http\Controllers\Users;

use App\Actions\Users\CreateUserAction;
use App\Http\Requests\Users\StoreUserRequest;
use Illuminate\Http\RedirectResponse;

class UserController extends Controller
{
    public function store(
        StoreUserRequest $request,
        CreateUserAction $action
    ): RedirectResponse {
        $user = $action->execute($request->validated());

        return redirect()
            ->route('users.show', $user)
            ->with('success', 'Usuario creado exitosamente.');
    }
}
```

## Uso en Jobs

```php
<?php

namespace App\Jobs;

use App\Actions\Orders\ProcessOrderAction;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessOrderJob implements ShouldQueue
{
    use Queueable;

    public function __construct(
        public Order $order
    ) {}

    public function handle(ProcessOrderAction $action): void
    {
        $action->execute($this->order);
    }
}
```

## Convenciones

1. **Nombre**: `{Verbo}{Nombre}Action` (CreateUserAction, ProcessOrderAction)
2. **Ubicación**: `app/Actions/{Funcionalidad}/`
3. **Método principal**: `execute()`
4. **Usar transacciones** para operaciones múltiples
5. **Inyección de dependencias** en constructor
6. **Type hints explícitos** para parámetros y retornos
7. **PHPDoc** para arrays con shape definitions
