In Laravel Factories, what is the difference from "state" and "defineAs"?
The answer before says that defineAs
is like an alias or a shorthand name but it is wrong! If you make:
factory('user')->create(); //it won't work
defineAs
and states are pretty much the same with a slightly difference.
In version prior to 5.2 states were called states https://laravel.com/docs/5.2/testing#model-factories
So defineAs
creates a different model type when you are creating a model, based in a raw model to set common attributes like this:
$factory->define(App\User::class, function ($faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => str_random(10),
'remember_token' => str_random(10),
'admin' => false,
];
});
$factory->defineAs(App\User::class, 'admin', function ($faker) use ($factory) {
$user = $factory->raw(App\User::class);
return array_merge($user, ['admin' => true]);
});
while states
are doing the same but in a better fashion way like this:
$factory->state(App\User::class, 'address', function ($faker) {
return [
'admin' => true,
];
});
Or even without a callback, just an array:
$factory->state(App\User::class, 'address', [
'admin' => true,
});
The other difference is that define
fires an event (afterCreating) called once the object is persisted in database and states
will fire an event afterCreatingState
.
Also, you can create an object with multiple states like this:
factory(App\User::class)->states('admin', 'disable')->create()
The methods state
and defineAs
serve completely different purposes.
define
and defineAs
You register a factory for a model using the define
method which you provide with a class and a callback. For example, if you are creating a factory for the User
model then you would register it like this:
$factory->define(App\User::class, function (Faker $faker) {
// set values here
});
Then you would call the factory like so:
factory(App\User::class)->make();
However, sometimes you may wish to register a factory using a name instead of the class, so that you could call the factory like this:
factory('user')->make();
That's where defineAs
comes in: defineAs
accepts a class (e.g: App\User::class
) and a name. For example:
$factory->define(App\User::class, 'user', function (Faker $faker) {
// set values here
});
defineAs
isn't documented but you can find it in the Eloquent source.
Factory States
Factory States are used for generating models with a specific set of attributes:
States allow you to define discrete modifications that can be applied to your model factories in any combination.
For example, your User
model may have an additional is_admin
field which determines if the user is an admin or not. You can create a state to allow for a user who is an admin to be generated through the factory.
First you define your state (where admin
is the name):
$factory->state(App\User::class, 'admin', [
'is_admin' => true,
]);
Then when generating your user you pass in the admin
state:
factory(App\User::class)->states('admin')->make();
This means that you can have a single factory for your User
model that supports many different types of User; you could create a state for banned users, or users who have a picture associated with their account, all within the same factory. This is extra beneficial because it means developers don't need to be concerned with the underlying structure when using factories, and if the underlying structure changes (e.g: is_admin
becomes administrator_at
) only the factory needs to be changed.