stemble/laravel-doctrine-factory
Installation:
composer require stemble/laravel-doctrine-factory
Add the service provider to config/app.php:
Stemble\DoctrineFactory\DoctrineFactoryServiceProvider::class,
Entity Setup:
Add the HasFactory trait to your Doctrine entity:
use Stemble\DoctrineFactory\HasFactory;
#[ORM\Entity]
class User implements UserInterface
{
use HasFactory;
// ...
}
Create a Factory: Generate a factory using Artisan:
php artisan make:factory UserFactory --model=App\Entity\User
The factory will be placed in database/factories/UserFactory.php.
Define Factory:
namespace Database\Factories;
use App\Entity\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
protected $model = User::class;
public function definition()
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
// ...
];
}
}
First Use Case: Create a user in a test:
use App\Entity\User;
use Database\Factories\UserFactory;
$user = UserFactory::new()->create();
Basic Creation:
// Create a single entity
$user = UserFactory::new()->create();
// Create multiple entities
$users = UserFactory::new()->count(5)->create();
States: Define reusable states in the factory:
public function definition()
{
return [
'name' => 'Default User',
];
}
public function admin()
{
return $this->state([
'name' => 'Admin User',
'role' => 'admin',
]);
}
Usage:
$admin = UserFactory::new()->admin()->create();
Relationships:
Use has() and for() for relationships:
// Create a user with posts
$user = UserFactory::new()->hasPosts(3)->create();
// Create posts for a user
$posts = PostFactory::new()->for($user)->create();
Sequences: Generate sequential data:
$users = UserFactory::new()->count(5)->sequence(
function (Factory $factory) {
return ['name' => 'User ' . $factory->index + 1];
}
)->create();
Callbacks:
Use afterMaking and afterCreating:
public function configure()
{
return $this->afterCreating(function (User $user) {
// Post-create logic
});
}
Testing: Use factories in PHPUnit tests for consistent test data:
public function test_user_creation()
{
$user = UserFactory::new()->create();
$this->assertDatabaseHas('users', ['email' => $user->email]);
}
Seeding:
Seed your database with factories in DatabaseSeeder.php:
public function run()
{
User::factory()->count(10)->create();
}
Custom Attributes: Override attributes dynamically:
$user = UserFactory::new()->create([
'email' => 'custom@example.com',
]);
Entity Manager Awareness:
The package uses Doctrine's EntityManager under the hood. Ensure your entity manager is properly configured and injected if you encounter issues with entity persistence.
State Conflicts: States can override each other unexpectedly. Define states carefully and test combinations:
// Avoid this if 'admin' and 'premium' states both set 'role'
$user = UserFactory::new()->admin()->premium()->create();
Relationship Loading:
Relationships (has(), for()) are not loaded by default. Use with() to eager-load:
$user = UserFactory::new()->hasPosts()->with('posts')->create();
Faker Integration:
The package relies on Faker for fake data. Ensure Faker is installed (fakerphp/faker) and configured correctly.
Transaction Handling: Factories create entities in a transaction by default. Disable with:
UserFactory::new()->create(['transaction' => false]);
Factory Not Found:
Ensure the factory class name matches the model name (e.g., UserFactory for User model) and is placed in database/factories/.
Entity Not Persisting:
Check if the EntityManager is properly injected or if the entity has required annotations (e.g., @ORM\Entity).
State Not Applying: Verify that states are defined as methods (not properties) and return the correct array structure.
Reuse Factories: Extend factories for reusable configurations:
class AdminUserFactory extends UserFactory
{
public function definition()
{
return parent::definition()->merge([
'role' => 'admin',
]);
}
}
Customize Faker: Override Faker instances for locale-specific data:
public function configure()
{
return $this->state(new \Faker\Generator());
}
Laravel Mixins: Use Laravel's factory mixins for dynamic attributes:
User::factory()->state(new class {
protected $attributes = [];
public function __invoke(Factory $factory)
{
return $this->attributes;
}
});
Performance: For bulk operations, disable callbacks and transactions:
UserFactory::new()->count(1000)->disableOriginalEvents()->create();
Doctrine Events:
Listen to Doctrine lifecycle events (e.g., prePersist) alongside factory callbacks for additional control.
How can I help you explore Laravel packages today?