Claude Code Plugins

Community-maintained marketplace

Feedback

Create Laravel model factories with type-safe state methods for generating test data. Use when creating factories, generating test data, seeding databases, or when user mentions factories, test data, fake data, or model factories.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name creating-factories
description Create Laravel model factories with type-safe state methods for generating test data. Use when creating factories, generating test data, seeding databases, or when user mentions factories, test data, fake data, or model factories.

Create Laravel Model Factories

Create model factories with type-safe state methods for generating test data. Factories produce realistic model instances for testing, with composable state methods that configure specific scenarios like admin users or unpublished posts.

File Structure

Factories are stored in the database/factories directory:

database/factories/{Model}Factory.php

Examples:

  • database/factories/UserFactory.php
  • database/factories/OrderFactory.php
  • database/factories/ProductFactory.php

Core Conventions

1. Factory Structure

<?php

declare(strict_types=1);

namespace Database\Factories;

use App\Models\{Model};
use Illuminate\Database\Eloquent\Factories\Factory;
use Override;

/**
 * @extends Factory<{Model}>
 */
final class {Model}Factory extends Factory
{
    protected $model = {Model}::class;

    #[Override]
    public function definition(): array
    {
        return [
            'field' => fake()->word(),
        ];
    }

    public function stateName(): self
    {
        return $this->state(fn (array $attributes): array => [
            'field' => 'specific-value',
        ]);
    }
}

Key Requirements:

  • Always include declare(strict_types=1);
  • Use final class modifier
  • Extend Factory base class
  • Add @extends Factory<Model> PHPDoc
  • Set protected $model property
  • Use #[Override] on definition() method
  • Type hint state methods returning self
  • Use fake() helper for fake data

2. Definition Method

#[Override]
public function definition(): array
{
    return [
        'name' => fake()->name(),
        'email' => fake()->unique()->safeEmail(),
        'password' => Hash::make('password'),
        'created_at' => now(),
    ];
}

3. State Methods

public function unverified(): self
{
    return $this->state(fn (array $attributes): array => [
        'email_verified_at' => null,
    ]);
}

public function admin(): self
{
    return $this->state(fn (array $attributes): array => [
        'role' => 'admin',
    ]);
}

Examples

Example 1: User Factory

<?php

declare(strict_types=1);

namespace Database\Factories;

use App\Models\User;
use App\Support\Localisation\Facades\Localisation;
use App\Support\TwoFactorAuthentication\Facades\TwoFactorAuthentication;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Override;

/**
 * @extends Factory<User>
 */
final class UserFactory extends Factory
{
    protected $model = User::class;

    #[Override]
    public function definition(): array
    {
        return [
            'name' => fake()->name(),
            'email' => fake()->unique()->safeEmail(),
            'language' => Localisation::getDefaultLocale(),
            'password' => Hash::make('password'),
            'two_factor_secret' => null,
            'two_factor_recovery_codes' => null,
            'remember_token' => Str::random(10),
            'avatar_path' => null,
            'email_verified_at' => now(),
            'two_factor_confirmed_at' => null,
        ];
    }

    public function unverified(): self
    {
        return $this->state(fn (array $attributes): array => [
            'email_verified_at' => null,
        ]);
    }

    public function withTwoFactorAuth(): self
    {
        return $this->state(fn (array $attributes): array => [
            'two_factor_secret' => TwoFactorAuthentication::generateSecretKey(),
            'two_factor_recovery_codes' => ['recovery-code-1', 'recovery-code-2'],
            'two_factor_confirmed_at' => now(),
        ]);
    }

    public function withUnconfirmedTwoFactorAuth(): self
    {
        return $this->state(fn (array $attributes): array => [
            'two_factor_secret' => TwoFactorAuthentication::generateSecretKey(),
            'two_factor_recovery_codes' => ['recovery-code-1', 'recovery-code-2'],
        ]);
    }

    public function withAvatar(): self
    {
        return $this->state(fn (array $attributes): array => [
            'avatar_path' => UploadedFile::fake()->image('avatar.jpg')->storePublicly('avatars', 'public'),
        ]);
    }
}

Example 2: Factory with Relationships

<?php

declare(strict_types=1);

namespace Database\Factories;

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

/**
 * @extends Factory<Order>
 */
final class OrderFactory extends Factory
{
    protected $model = Order::class;

    #[Override]
    public function definition(): array
    {
        return [
            'user_id' => User::factory(),
            'total' => fake()->numberBetween(1000, 100000),
            'status' => 'pending',
            'notes' => fake()->sentence(),
        ];
    }

    public function completed(): self
    {
        return $this->state(fn (array $attributes): array => [
            'status' => 'completed',
            'completed_at' => now(),
        ]);
    }

    public function cancelled(): self
    {
        return $this->state(fn (array $attributes): array => [
            'status' => 'cancelled',
            'cancelled_at' => now(),
        ]);
    }

    public function forUser(User $user): self
    {
        return $this->state(fn (array $attributes): array => [
            'user_id' => $user->id,
        ]);
    }
}

Example 3: Factory with Enums

<?php

declare(strict_types=1);

namespace Database\Factories;

use App\Enums\PostStatus;
use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Override;

/**
 * @extends Factory<Post>
 */
final class PostFactory extends Factory
{
    protected $model = Post::class;

    #[Override]
    public function definition(): array
    {
        return [
            'user_id' => User::factory(),
            'title' => fake()->sentence(),
            'body' => fake()->paragraphs(3, true),
            'status' => PostStatus::Draft,
            'published_at' => null,
        ];
    }

    public function published(): self
    {
        return $this->state(fn (array $attributes): array => [
            'status' => PostStatus::Published,
            'published_at' => now(),
        ]);
    }

    public function draft(): self
    {
        return $this->state(fn (array $attributes): array => [
            'status' => PostStatus::Draft,
            'published_at' => null,
        ]);
    }
}

Using Factories

In Tests

// Create single model
$user = User::factory()->create();

// Create with attributes
$user = User::factory()->create([
    'email' => 'test@example.com',
]);

// Create with state
$user = User::factory()->unverified()->create();

// Create multiple
$users = User::factory()->count(10)->create();

// Make without persisting
$user = User::factory()->make();

// Chain states
$user = User::factory()
    ->unverified()
    ->withTwoFactorAuth()
    ->create();

In Seeders

User::factory()->count(100)->create();

Order::factory()
    ->count(50)
    ->completed()
    ->create();

Anti-Patterns

❌ Don't Do This

// Don't skip @extends PHPDoc
final class UserFactory extends Factory // ❌ Missing @extends

// Don't skip #[Override] on definition()
public function definition(): array // ❌ Missing #[Override]

// Don't skip type hint on state methods
public function unverified() // ❌ Type hint return as self
{
    return $this->state([...]);
}

// Don't use actual data in definition()
public function definition(): array
{
    return [
        'email' => 'test@example.com', // ❌ Use fake()
    ];
}

// Don't forget $model property
final class UserFactory extends Factory
{
    // ❌ Missing protected $model
}

// Don't use mutable class
class UserFactory extends Factory // ❌ Use final class

✅ Do This Instead

// Include @extends PHPDoc
/**
 * @extends Factory<User>
 */
final class UserFactory extends Factory

// Use #[Override] on definition()
#[Override]
public function definition(): array

// Type hint state methods
public function unverified(): self
{
    return $this->state(fn (array $attributes): array => [...]);
}

// Use fake() helper
public function definition(): array
{
    return [
        'email' => fake()->safeEmail(),
    ];
}

// Set $model property
protected $model = User::class;

// Use final class
final class UserFactory extends Factory

Quality Standards

  • All factories must pass PHPStan level 8
  • 100% type coverage required
  • Code formatted with Pint
  • Refactored with Rector
  • Use fake() for all generated data
  • Provide useful state methods for common scenarios