Eloquent: Factories
Introduction
When testing your application or seeding your database, you may need to insert a few records into your database. Instead of manually specifying the value of each column, Laravel allows you to define a set of default attributes for each of your Eloquent models using model factories.
To see an example of how to write a factory, take a look at the database/factories/UserFactory.php
file in your application. This factory is included with all new Laravel applications and contains the following factory definition:
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
}
As you can see, in their most basic form, factories are classes that extend Laravel's base factory class and define a definition
method. The definition
method returns the default set of attribute values that should be applied when creating a model using the factory.
Via the fake
helper, factories have access to the Faker PHP library, which allows you to conveniently generate various kinds of random data for testing and seeding.
You can set your application's Faker locale by adding a faker_locale
option to your config/app.php
configuration file.
Defining Model Factories
Generating Factories
To create a factory, execute the make:factory
Artisan command:
php artisan make:factory PostFactory
The new factory class will be placed in your database/factories
directory.
Model & Factory Discovery Conventions
Once you have defined your factories, you may use the static factory
method provided to your models by the Illuminate\Database\Eloquent\Factories\HasFactory
trait in order to instantiate a factory instance for that model.
The HasFactory
trait's factory
method will use conventions to determine the proper factory for the model the trait is assigned to. Specifically, the method will look for a factory in the Database\Factories
namespace that has a class name matching the model name and is suffixed with Factory
. If these conventions do not apply to your particular application or factory, you may overwrite the newFactory
method on your model to return an instance of the model's corresponding factory directly:
use Database\Factories\Administration\FlightFactory;
/**
* Create a new factory instance for the model.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory()
{
return FlightFactory::new();
}
Next, define a model
property on the corresponding factory:
use App\Administration\Flight;
use Illuminate\Database\Eloquent\Factories\Factory;
class FlightFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Flight::class;
}
Factory States
State manipulation methods allow you to define discrete modifications that can be applied to your model factories in any combination. For example, your Database\Factories\UserFactory
factory might contain a suspended
state method that modifies one of its default attribute values.
State transformation methods typically call the state
method provided by Laravel's base factory class. The state
method accepts a closure which will receive the array of raw attributes defined for the factory and should return an array of attributes to modify:
/**
* Indicate that the user is suspended.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function suspended()
{
return $this->state(function (array $attributes) {
return [
'account_status' => 'suspended',
];
});
}
"Trashed" State
If your Eloquent model can be soft deleted, you may invoke the built-in trashed
state method to indicate that the created model should already be "soft deleted". You do not need to manually define the trashed
state as it is automatically available to all factories:
use App\Models\User;
$user = User::factory()->trashed()->create();
Factory Callbacks
Factory callbacks are registered using the afterMaking
and afterCreating
methods and allow you to perform additional tasks after making or creating a model. You should register these callbacks by defining a configure
method on your factory class. This method will be automatically called by Laravel when the factory is instantiated:
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* Configure the model factory.
*
* @return $this
*/
public function configure()
{
return $this->afterMaking(function (User $user) {
//
})->afterCreating(function (User $user) {
//
});
}
// ...
}
Creating Models Using Factories
Instantiating Models
Once you have defined your factories, you may use the static factory
method provided to your models by the Illuminate\Database\Eloquent\Factories\HasFactory
trait in order to instantiate a factory instance for that model. Let's take a look at a few examples of creating models. First, we'll use the make
method to create models without persisting them to the database:
use App\Models\User;
$user = User::factory()->make();
You may create a collection of many models using the count
method:
$users = User::factory()->count(3)->make();
Applying States
You may also apply any of your states to the models. If you would like to apply multiple state transformations to the models, you may simply call the state transformation methods directly:
$users = User::factory()->count(5)->suspended()->make();
Overriding Attributes
If you would like to override some of the default values of your models, you may pass an array of values to the make
method. Only the specified attributes will be replaced while the rest of the attributes remain set to their default values as specified by the factory:
$user = User::factory()->make([
'name' => 'Abigail Otwell',
]);
Alternatively, the state
method may be called directly on the factory instance to perform an inline state transformation:
$user = User::factory()->state([
'name' => 'Abigail Otwell',
])->make();
Mass assignment protection is automatically disabled when creating models using factories.
Persisting Models
The create
method instantiates model instances and persists them to the database using Eloquent's save
method:
use App\Models\User;
// Create a single App\Models\User instance...
$user = User::factory()->create();
// Create three App\Models\User instances...
$users = User::factory()->count(3)->create();
You may override the factory's default model attributes by passing an array of attributes to the create
method:
$user = User::factory()->create([
'name' => 'Abigail',
]);
Sequences
Sometimes you may wish to alternate the value of a given model attribute for each created model. You may accomplish this by defining a state transformation as a sequence. For example, you may wish to alternate the value of an admin
column between Y
and N
for each created user:
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Sequence;
$users = User::factory()
->count(10)
->state(new Sequence(
['admin' => 'Y'],
['admin' => 'N'],
))
->create();