Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Laravel Factories, what is the difference from "state" and "defineAs"?

What is the difference, in Laravel's Factories, from using the method state and the method defineAs?

Is state just an extension of the base method and defineAs a whole different definition? Could you present some examples to make it easier to understand?

like image 292
Johny Serpa Avatar asked Apr 23 '18 11:04

Johny Serpa


2 Answers

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.

like image 181
sam Avatar answered Nov 09 '22 01:11

sam


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()
like image 44
faiverson Avatar answered Nov 09 '22 02:11

faiverson