> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Factorías de Eloquent

> Aprende a generar datos ficticios para tests y seeding de forma eficiente con las factorías de modelos.

## Qué son las factorías

En los tests y en el seeding de la base de datos necesitas insertar registros.
En lugar de indicar manualmente los valores de cada columna, con las **factorías de modelos** de Laravel puedes definir un conjunto de atributos por defecto para cada modelo Eloquent.

Todas las nuevas aplicaciones Laravel incluyen `database/factories/UserFactory.php`.

```php theme={null}
namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class UserFactory extends Factory
{
    // Cachea la misma contraseña para no rehash cada vez
    protected static ?string $password;

    public function definition(): array
    {
        return [
            'name' => fake()->name(),
            'email' => fake()->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => static::$password ??= Hash::make('password'),
            'remember_token' => Str::random(10),
        ];
    }
}
```

Con el helper `fake()` tienes acceso a la librería [Faker](https://github.com/FakerPHP/Faker), que genera todo tipo de datos aleatorios.

```mermaid theme={null}
flowchart LR
    F["Factory<br>database/factories/UserFactory"] -->|"make() / create()"| M["Instancia del modelo<br>App\\Models\\User"]
    M -->|"create()"| DB[("Base de datos")]
    F -->|"Faker"| R["Datos aleatorios<br>name, email, ..."]
    R --> F
```

<Info>
  Puedes cambiar la localización de Faker con la opción `faker_locale` de `config/app.php`.
</Info>

## Generar una factoría

Crea una factoría con el comando Artisan `make:factory`.

```shell theme={null}
php artisan make:factory PostFactory
```

La nueva clase se ubica en el directorio `database/factories`.

### Detección automática de modelo y factoría

Si el modelo usa el trait `HasFactory`, Laravel localiza automáticamente su factoría.
Busca dentro del namespace `Database\Factories` una clase cuyo nombre sea el del modelo con el sufijo `Factory`.

Si la convención no coincide, indícalo explícitamente con el atributo `UseFactory`.

```php theme={null}
use Illuminate\Database\Eloquent\Attributes\UseFactory;
use Database\Factories\Administration\FlightFactory;

#[UseFactory(FlightFactory::class)]
class Flight extends Model
{
    // ...
}
```

## Definir una factoría

### Método `definition()`

Los atributos por defecto se definen en el método `definition()`.

```php theme={null}
namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

class PostFactory extends Factory
{
    public function definition(): array
    {
        return [
            'user_id' => \App\Models\User::factory(),
            'title' => fake()->sentence(),
            'content' => fake()->paragraphs(3, true),
            'published_at' => fake()->optional()->dateTimeBetween('-1 year', 'now'),
        ];
    }
}
```

Métodos de Faker más habituales:

| Método                          | Dato de ejemplo          |
| ------------------------------- | ------------------------ |
| `fake()->name()`                | `John Doe`               |
| `fake()->email()`               | `john@example.com`       |
| `fake()->sentence()`            | Frase aleatoria          |
| `fake()->paragraph()`           | Párrafo aleatorio        |
| `fake()->numberBetween(1, 100)` | Entero entre `1` y `100` |
| `fake()->dateTime()`            | Fecha y hora aleatoria   |
| `fake()->boolean()`             | `true` / `false`         |

## Estados de la factoría (states)

Los métodos de estado permiten definir variantes concretas para la factoría.

```php theme={null}
use Illuminate\Database\Eloquent\Factories\Factory;

class UserFactory extends Factory
{
    public function definition(): array
    {
        return [
            'name' => fake()->name(),
            'email' => fake()->unique()->safeEmail(),
            'account_status' => 'active',
        ];
    }

    // Estado de usuario suspendido
    public function suspended(): static
    {
        return $this->state(fn (array $attributes) => [
            'account_status' => 'suspended',
        ]);
    }

    // Estado de usuario administrador
    public function admin(): static
    {
        return $this->state(fn (array $attributes) => [
            'is_admin' => true,
        ]);
    }
}
```

Los estados se pueden combinar.

```php theme={null}
$user = User::factory()->suspended()->create();
$admin = User::factory()->admin()->create();
```

### Estado de soft delete

En los modelos con soft delete dispones del estado integrado `trashed()`.

```php theme={null}
$user = User::factory()->trashed()->create();
```

## Callbacks de la factoría

Los métodos `afterMaking` y `afterCreating` te permiten ejecutar lógica adicional tras generar el modelo.

```php theme={null}
namespace Database\Factories;

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

class UserFactory extends Factory
{
    public function configure(): static
    {
        return $this->afterMaking(function (User $user) {
            // Se ejecuta tras make() (aún no guardado en BD)
        })->afterCreating(function (User $user) {
            // Se ejecuta tras create() (guardado en BD)
        });
    }

    // ...
}
```

También puedes registrar callbacks dentro de un método de estado.

```php theme={null}
public function withProfile(): static
{
    return $this->state(fn (array $attributes) => [])
        ->afterCreating(function (User $user) {
            $user->profile()->create([
                'bio' => fake()->paragraph(),
            ]);
        });
}
```

## Generar modelos

### `make()`: sin guardar en la BD

```php theme={null}
use App\Models\User;

// Genera 1 elemento
$user = User::factory()->make();

// Genera 3 (devuelve una colección)
$users = User::factory()->count(3)->make();
```

### `create()`: guarda en la BD

```php theme={null}
// Genera y guarda 1
$user = User::factory()->create();

// Genera y guarda 3
$users = User::factory()->count(3)->create();
```

### Sobrescribir atributos

Si pasas un array a `make()` o `create()`, se sobrescriben únicamente los atributos indicados.

```php theme={null}
$user = User::factory()->make([
    'name' => 'Ana García',
]);

$user = User::factory()->create([
    'name' => 'Luis Pérez',
    'email' => 'luis@example.com',
]);
```

También puedes usar `state` para sobrescribir de forma inline.

```php theme={null}
$user = User::factory()->state([
    'name' => 'María López',
])->make();
```

<Info>
  Al generar modelos con una factoría, la protección de asignación masiva se desactiva automáticamente.
</Info>

### Sequence

Cuando generas varios modelos y quieres alternar los valores, utiliza `Sequence`.

```php theme={null}
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Sequence;

$users = User::factory()
    ->count(10)
    ->state(new Sequence(
        ['admin' => 'Y'],
        ['admin' => 'N'],
    ))
    ->create();
// Se generarán 5 con admin='Y' y 5 con admin='N'
```

El método `sequence()` es una forma más concisa.

```php theme={null}
$users = User::factory()
    ->count(2)
    ->sequence(
        ['name' => 'Primer usuario'],
        ['name' => 'Segundo usuario'],
    )
    ->create();
```

También puedes generar valores dinámicos con una closure.

```php theme={null}
use Illuminate\Database\Eloquent\Factories\Sequence;

$users = User::factory()
    ->count(10)
    ->state(new Sequence(
        fn (Sequence $sequence) => ['name' => 'Usuario ' . $sequence->index],
    ))
    ->create();
```

## Factorías de relaciones

```mermaid theme={null}
flowchart TD
    UF["UserFactory"] -->|"has(PostFactory)"| PF["PostFactory"]
    PF -->|"for(UserFactory)"| UF
    UF -->|"hasAttached(RoleFactory)"| RF["RoleFactory"]

    UF -->|"create()"| U["Modelo User"]
    PF -->|"create()"| P["Modelo Post"]
    RF -->|"create()"| R["Modelo Role"]

    U -->|"hasMany"| P
    U -->|"belongsToMany"| R
```

### Has Many (uno a muchos)

El método `has()` crea modelos con una relación «uno a muchos».

```php theme={null}
use App\Models\Post;
use App\Models\User;

// Un User con 3 Posts
$user = User::factory()
    ->has(Post::factory()->count(3))
    ->create();
```

Con métodos mágicos (`has` + nombre en plural de la relación) queda más breve.

```php theme={null}
$user = User::factory()
    ->hasPosts(3)
    ->create();

// Sobrescribiendo atributos
$user = User::factory()
    ->hasPosts(3, ['published' => false])
    ->create();
```

### Belongs To (relación inversa)

Con `for()` indicas el modelo padre al que «pertenece».

```php theme={null}
use App\Models\Post;
use App\Models\User;

// 3 Posts pertenecientes a un usuario concreto
$posts = Post::factory()
    ->count(3)
    ->for(User::factory()->state(['name' => 'Ana García']))
    ->create();

// Usar un modelo existente como padre
$user = User::factory()->create();
$posts = Post::factory()->count(3)->for($user)->create();
```

Versión con métodos mágicos:

```php theme={null}
$posts = Post::factory()
    ->count(3)
    ->forUser(['name' => 'Ana García'])
    ->create();
```

### Many to Many (muchos a muchos)

Con `hasAttached()` gestionas las relaciones muchos a muchos. También puedes indicar atributos para la tabla pivote.

```php theme={null}
use App\Models\Role;
use App\Models\User;

$user = User::factory()
    ->hasAttached(
        Role::factory()->count(3),
        ['active' => true]  // Atributos de la tabla pivote
    )
    ->create();
```

Versión con métodos mágicos:

```php theme={null}
$user = User::factory()
    ->hasRoles(1, ['name' => 'Editor'])
    ->create();
```

### Relaciones polimórficas

Puedes usar `has()` o los métodos mágicos igual que en un «uno a muchos» normal.

```php theme={null}
use App\Models\Post;

$post = Post::factory()->hasComments(3)->create();
```

Las relaciones `morphTo` no admiten métodos mágicos. Debes indicar el nombre de la relación en `for()`.

```php theme={null}
$comments = Comment::factory()->count(3)->for(
    Post::factory(), 'commentable'
)->create();
```

### Definir relaciones dentro de la factoría

Si asignas otra factoría a una clave foránea en `definition()`, el modelo padre se genera automáticamente cuando se crea el hijo.

```php theme={null}
class PostFactory extends Factory
{
    public function definition(): array
    {
        return [
            'user_id' => \App\Models\User::factory(),
            'title' => fake()->sentence(),
            'content' => fake()->paragraph(),
        ];
    }
}
```

### `recycle()`: reutilizar un modelo existente

Cuando quieras usar la misma instancia de un modelo en varias relaciones, utiliza `recycle()`.

```php theme={null}
// Reutilizar el mismo Airline para Ticket y Flight
Ticket::factory()
    ->recycle(Airline::factory()->create())
    ->create();

// Elegir aleatoriamente de una colección
$airlines = Airline::factory()->count(3)->create();
Ticket::factory()->count(10)->recycle($airlines)->create();
```

## Uso en seeders

Puedes invocar las factorías desde `DatabaseSeeder` o desde otros seeders.

```php theme={null}
namespace Database\Seeders;

use App\Models\User;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // Crea 10 usuarios, cada uno con 3 posts
        User::factory()
            ->count(10)
            ->hasPosts(3)
            ->create();
    }
}
```

Ejecutar los seeders:

```shell theme={null}
php artisan db:seed
```

## Uso en tests

En los tests las factorías se combinan con el trait `RefreshDatabase`.

```php theme={null}
namespace Tests\Feature;

use App\Models\User;
use App\Models\Post;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PostTest extends TestCase
{
    use RefreshDatabase;

    public function test_user_can_view_their_posts(): void
    {
        $user = User::factory()->create();
        $posts = Post::factory()->count(3)->for($user)->create();

        $response = $this->actingAs($user)
            ->get('/dashboard');

        $response->assertOk();
        $response->assertSee($posts->first()->title);
    }

    public function test_suspended_user_cannot_post(): void
    {
        $user = User::factory()->suspended()->create();

        $response = $this->actingAs($user)
            ->post('/posts', ['title' => 'Prueba']);

        $response->assertForbidden();
    }
}
```

`RefreshDatabase` reinicia la base de datos en cada prueba, evitando interferencias entre ellas.

<Tip>
  La API de las factorías es igual cuando pruebas con Pest.
  Utiliza `uses(RefreshDatabase::class)` para reiniciar la base de datos.
</Tip>

## Próximos pasos

<Card title="Seeding de la base de datos" icon="seedling" href="/es/seeding">
  Aprende a combinar seeders y factorías para cargar datos iniciales.
</Card>

<Card title="Introducción a los tests" icon="flask" href="/es/testing">
  Descubre las herramientas de testing de Laravel y cómo usar el trait RefreshDatabase.
</Card>


## Related topics

- [Pruebas de base de datos](/es/database-testing.md)
- [Scopes de Eloquent](/es/advanced/eloquent-scopes.md)
- [API resources de Eloquent](/es/eloquent-resources.md)
- [Casts personalizados de Eloquent](/es/advanced/eloquent-casts.md)
- [Accesores, mutadores y casts de Eloquent](/es/eloquent-mutators.md)
