DEV Community

Cover image for Our way: Models, Migrations, Factories and Seeders.
Robson Tenório
Robson Tenório

Posted on • Edited on

Our way: Models, Migrations, Factories and Seeders.

👉 Go to Summary

There is no wrong or right way, there is our way.

-- Someone

.
.
.

Models

  1. It should represent primarily ORM mapping.
  2. It does not contain use cases, see actions.
  3. It can have small helper methods, computed properties, or scopes to make it easy to query data.
class User extends Model{

    // Relationships
    function country(): BelongsTo { ... }

    // Helper method
    function isAdmin(): bool { ... }    

    // Query scope
    function scopeActive(Builder $query) { ... }

    // Computed attribute
    function getShortNameAttribute(): string { ... }
}
Enter fullscreen mode Exit fullscreen mode

Migrations

  1. Use normalized modeling.
  2. Stick with convention xxxx_id for FKs.
  3. Comment edge case columns.
  4. Rememberindexes (performance).

Schema::create('users', function (Blueprint $table) {
   $table->id();
   $table->foreignId('country_id')->constrained();
   $table->string('name')->index();
   $table->string('cpf')->comment('Brazilian social number');

});
Enter fullscreen mode Exit fullscreen mode

Seeders

  1. Must contain all default values to bootstrap app first time.
  2. Mostly it represents domain business value that should be mapped into model constants.
  3. Remember seeders can run many times, so put a IF.
class PaymentTypesSeeder extends Seeder
{   
    public function run()
    {
        // Avoid run twice
        if (PaymentType::count()) {
            return;
        }

        // Insert initial data when app bootstraps
        PaymentType::insert([...])
    }
}
Enter fullscreen mode Exit fullscreen mode

Factories

  1. If it matters use a pre-seeded value.
  2. If it does not matter call a factory.
class UserFactory extends Factory
{
   public function definition()
   {       
      return [            
            // It is a well known value, should be one from seeder 
            'prefered_payment_type_id' => PaymentType::inRandomOrder()->first(),
            // does not matter who is the parent user
            'parent_id' => User::factory(), 
            'name' => $this->faker->name(),
             // ....
        ];
    }

Enter fullscreen mode Exit fullscreen mode

Top comments (0)