Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Polymorphic Database Seeder Factory

How can I create a database seeder factory for the following configuration?

User

// create_users_table.php
Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    ...
}

// User.php
public function notes()
{
    return $this->morphMany('App\Note', 'noteable');
}

Complex

// create_complex_table.php
Schema::create('complex', function (Blueprint $table) {
    $table->increments('id');
    ...
}

// Complex.php
public function notes()
{
    return $this->morphMany('App\Note', 'noteable');
}

Notes

// create_notes_table.php
Schema::create('notes', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('noteable_id');
    $table->string('noteable_type');
    ...
}

// Note.php
public function noteable()
{
    return $this->morphTo();
}

I am struggling to see the most robust way of ensuring that I am not just filling in random id's that may not exist.

like image 205
HyperionX Avatar asked Mar 10 '18 04:03

HyperionX


People also ask

What is difference between factory and seeder in Laravel?

Database seeder is used to populate tables with data. Model factories is a convenient centralized place to define how your models should be populated with fake data.

Does Laravel have factory?

Laravel has a feature called model factories that allows you to build fake data for your models. It is very useful for testing and seeding fake data into your database to see your code in action before any real user data comes in.

What is Laravel 8 factory?

According to Laravel's official documentation, “factories are classes that extend Laravel's base factory class and define a model property and definition method.” Just think about it this way.

What is polymorphic relationship in Laravel?

A one-to-one polymorphic relationship is a situation where one model can belong to more than one type of model but on only one association. A typical example of this is featured images on a post and an avatar for a user. The only thing that changes however is how we get the associated model by using morphOne instead.


2 Answers

I have improved upon HyperionX's answer and removed the static elements from it.

$factory->define(App\Note::class, function (Faker $faker) {
    $noteable = [
        App\User::class,
        App\Complex::class,
    ]; // Add new noteables here as we make them
    $noteableType = $faker->randomElement($noteables);
    $noteable = factory($noteableType)->create();

    return [
        'noteable_type' => $noteableType,
        'noteable_id' => $noteable->id,
        ...
    ];
});

Basically, we pick one of the noteable classes at random, then call it's own factory to get an instance of noteable, thus we get rid of the staticness of the OP's answer.

like image 112
Barracuda Avatar answered Sep 21 '22 12:09

Barracuda


If you are using a morph map the given solutions won't work because the type won't be the same as the class name.

This will work in combination with a morph map.

Until Laravel 7

$factory->define(App\Note::class, function (Faker $faker) {
    $noteable = $faker->randomElement([
        App\User::class,
        App\Complex::class,
    ]);

    return [
        'noteable_id' => factory($noteable),
        'noteable_type' => array_search($noteable, Relation::$morphMap),
        ...
    ];
});

From Laravel 8

public function definition(): array
{
    /** @var HasFactory $noteable */
    $noteable = $this->faker->randomElement([
        App\User::class,
        App\Complex::class,
    ]);

    return [
        'noteable_type' => array_search($noteable, Relation::$morphMap),
        'noteable_id' => $noteable::factory(),
    ];
}

More information about morph map could be found here: https://laravel.com/docs/8.x/eloquent-relationships#custom-polymorphic-types

like image 28
maartenpaauw Avatar answered Sep 24 '22 12:09

maartenpaauw