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

# Eloquent-Factories

> Erläutert, wie Sie mit Model-Factories effizient Fake-Daten für Tests und Seeding erzeugen.

## Was ist eine Factory?

Bei Tests und beim Seeding müssen Datensätze in die Datenbank eingefügt werden.
Statt für jede Spalte einen Wert von Hand anzugeben, definieren Sie mit einer **Model-Factory** in Laravel einen Satz an Standardattributen pro Eloquent-Modell.

Jede neue Laravel-Anwendung enthält die Datei `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
{
    // Das gleiche Passwort nicht jedes Mal neu hashen
    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),
        ];
    }
}
```

Über den Helper `fake()` steht die Bibliothek [Faker](https://github.com/FakerPHP/Faker) zur Verfügung, mit der Sie verschiedenste Zufallsdaten erzeugen können.

```mermaid theme={null}
flowchart LR
    F["Factory<br>database/factories/UserFactory"] -->|"make() / create()"| M["Model-Instanz<br>App\\Models\\User"]
    M -->|"create()"| DB[("Datenbank")]
    F -->|"Faker"| R["Zufallsdaten<br>name, email, ..."]
    R --> F
```

<Info>
  Die Faker-Locale können Sie in `config/app.php` über die Option `faker_locale` ändern.
</Info>

## Factory erzeugen

Erzeugen Sie eine Factory über den Artisan-Befehl `make:factory`.

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

Neue Factory-Klassen werden im Verzeichnis `database/factories` abgelegt.

### Automatische Erkennung von Modell und Factory

Wenn ein Modell das Trait `HasFactory` verwendet, findet Laravel die zugehörige Factory automatisch.
Gesucht wird im Namespace `Database\Factories` nach einer Klasse mit dem Namen des Modells plus `Factory`.

Wenn die Namenskonvention nicht passt, können Sie die Zuordnung mit dem Attribut `UseFactory` explizit angeben.

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

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

## Factory definieren

### Methode `definition()`

Die zentrale Methode `definition()` liefert die Standardattribute.

```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'),
        ];
    }
}
```

Häufig genutzte Faker-Methoden im Überblick:

| Methode                         | Beispielausgabe                 |
| ------------------------------- | ------------------------------- |
| `fake()->name()`                | `John Doe`                      |
| `fake()->email()`               | `john@example.com`              |
| `fake()->sentence()`            | Zufälliger Satz                 |
| `fake()->paragraph()`           | Zufälliger Absatz               |
| `fake()->numberBetween(1, 100)` | Ganzzahl zwischen `1` und `100` |
| `fake()->dateTime()`            | Zufälliges Datum mit Uhrzeit    |
| `fake()->boolean()`             | `true` / `false`                |

## Factory States

Mit State-Methoden definieren Sie einzelne Varianten einer Factory.

```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',
        ];
    }

    // State für gesperrte Nutzer
    public function suspended(): static
    {
        return $this->state(fn (array $attributes) => [
            'account_status' => 'suspended',
        ]);
    }

    // State für Admin-Nutzer
    public function admin(): static
    {
        return $this->state(fn (array $attributes) => [
            'is_admin' => true,
        ]);
    }
}
```

States lassen sich kombinieren.

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

### State für Soft Deletes

Für Modelle mit Soft Deletes steht der eingebaute State `trashed()` bereit.

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

## Factory-Callbacks

Mit `afterMaking` und `afterCreating` fügen Sie nach dem Erzeugen zusätzliche Verarbeitungsschritte hinzu.

```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) {
            // Nach make() ausgeführt (nicht in der DB gespeichert)
        })->afterCreating(function (User $user) {
            // Nach create() ausgeführt (bereits in der DB)
        });
    }

    // ...
}
```

Auch innerhalb einer State-Methode können Callbacks registriert werden.

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

## Modelle erzeugen

### make() – nicht in der DB speichern

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

// Ein Modell erzeugen
$user = User::factory()->make();

// Drei Modelle erzeugen (Rückgabe als Collection)
$users = User::factory()->count(3)->make();
```

### create() – in der DB speichern

```php theme={null}
// Ein Modell erzeugen und speichern
$user = User::factory()->create();

// Drei Modelle erzeugen und speichern
$users = User::factory()->count(3)->create();
```

### Attribute überschreiben

Übergeben Sie an `make()` oder `create()` ein Array, um einzelne Attribute zu überschreiben.

```php theme={null}
$user = User::factory()->make([
    'name' => 'Yamada Taro',
]);

$user = User::factory()->create([
    'name' => 'Suzuki Hanako',
    'email' => 'hanako@example.com',
]);
```

Auch das Überschreiben inline über einen State ist möglich.

```php theme={null}
$user = User::factory()->state([
    'name' => 'Tanaka Ichiro',
])->make();
```

<Info>
  Beim Erzeugen von Modellen über eine Factory wird der Schutz vor Mass Assignment automatisch deaktiviert.
</Info>

### Sequence

Wenn Sie beim Erzeugen mehrerer Modelle Attribute abwechselnd variieren möchten, verwenden Sie `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();
// Fünfmal admin='Y', fünfmal admin='N'
```

Die Methode `sequence()` bietet eine kürzere Schreibweise.

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

Über eine Closure lassen sich Werte auch dynamisch erzeugen.

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

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

## Factories für Relationen

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

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

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

### Has Many (1:n)

Mit `has()` erzeugen Sie ein Modell mit einer 1:n-Relation.

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

// Nutzer mit drei Beiträgen erzeugen
$user = User::factory()
    ->has(Post::factory()->count(3))
    ->create();
```

Mit Magic-Methoden geht es kürzer (`has` + Plural-Form des Beziehungsnamens).

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

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

### Belongs To (umgekehrte Relation)

Mit `for()` geben Sie das zugehörige Parent-Modell an.

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

// Drei Beiträge für einen bestimmten Nutzer
$posts = Post::factory()
    ->count(3)
    ->for(User::factory()->state(['name' => 'Tanaka Hanako']))
    ->create();

// Ein vorhandenes Modell als Parent verwenden
$user = User::factory()->create();
$posts = Post::factory()->count(3)->for($user)->create();
```

Magic-Methoden-Variante:

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

### Many to Many (n:m)

Für n:m-Beziehungen verwenden Sie `hasAttached()`. Auch Attribute der Zwischentabelle können angegeben werden.

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

$user = User::factory()
    ->hasAttached(
        Role::factory()->count(3),
        ['active' => true]  // Attribute der Zwischentabelle
    )
    ->create();
```

Magic-Methoden-Variante:

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

### Polymorphe Relationen

Wie bei einer normalen 1:n-Relation können Sie `has()` oder die Magic-Methoden verwenden.

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

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

Für `morphTo`-Relationen stehen keine Magic-Methoden zur Verfügung. Geben Sie den Beziehungsnamen explizit an `for()` weiter.

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

### Relationen in der Factory

Weisen Sie in `definition()` einem Fremdschlüssel eine andere Factory zu, wird beim Erzeugen des Modells automatisch auch das Parent-Modell angelegt.

```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() – bestehende Modelle wiederverwenden

Wenn Sie in mehreren Relationen dieselbe Modellinstanz wiederverwenden möchten, nutzen Sie `recycle()`.

```php theme={null}
// Dieselbe Airline bei Ticket und Flight verwenden
Ticket::factory()
    ->recycle(Airline::factory()->create())
    ->create();

// Zufällig aus einer Collection wählen
$airlines = Airline::factory()->count(3)->create();
Ticket::factory()->count(10)->recycle($airlines)->create();
```

## Verwendung beim Seeding

Rufen Sie Factories im `DatabaseSeeder` oder aus einer Seeder-Klasse heraus auf.

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

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

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // 10 Nutzer, jeder mit 3 Beiträgen
        User::factory()
            ->count(10)
            ->hasPosts(3)
            ->create();
    }
}
```

Seeder ausführen:

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

## Verwendung in Tests

In Tests kombinieren Sie Factories mit dem 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' => 'Test']);

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

`RefreshDatabase` setzt die Datenbank zwischen den Tests zurück, damit sich die Daten der einzelnen Tests nicht gegenseitig beeinflussen.

<Tip>
  Bei Tests mit Pest verwenden Sie dieselbe Factory-API.
  Setzen Sie die Datenbank mit `uses(RefreshDatabase::class)` zurück.
</Tip>

## Nächste Schritte

<Card title="Datenbank-Seeding" icon="seedling" href="/de/seeding">
  Erfahren Sie, wie Sie Seeder und Factories kombinieren, um initiale Daten einzuspielen.
</Card>

<Card title="Einführung in Tests" icon="flask" href="/de/testing">
  Vertiefen Sie die Test-Funktionen von Laravel und die Nutzung des `RefreshDatabase`-Traits.
</Card>


## Related topics

- [Datenbanktests](/de/database-testing.md)
- [Datenbank-Seeding](/de/seeding.md)
- [Contracts](/de/contracts.md)
- [HTTP-Tests](/de/http-tests.md)
- [PHP-Attribute](/de/advanced/php-attributes.md)
