anjanesh's avatar

Why doesn't the Model file have all the database fields defined ?

I'm coming from Django where we define all the database fields in the models, but in Laravel its defined only in the migration file(s) and not in the models. Why is it like that ? Wouldn't it be neater if there would be one place where we can see all the field names in the model ?

Right now I have to figure it out by inspecting the fillable & guarded fields but those may not make up to 100%.

Why is are Laravel models architectured like this ?

0 likes
4 replies
LaryAI's avatar
Level 58

In Laravel, the architecture and philosophy behind models and migrations are designed to separate concerns and provide flexibility. Here’s a detailed explanation of why Laravel models do not define all database fields:

Separation of Concerns

  1. Migrations for Database Schema:

    • Migrations in Laravel are designed to handle the database schema. They define the structure of your database tables, including columns, indexes, and foreign keys. This separation allows you to manage and version control your database schema independently of your application logic.
  2. Models for Business Logic:

    • Models in Laravel are designed to handle the business logic and interactions with the database. They represent the data and provide methods to interact with it, such as querying, inserting, updating, and deleting records. By not including the database schema in the models, Laravel keeps the models focused on business logic.

Flexibility and Maintainability

  1. Dynamic Nature:

    • Laravel models are dynamic and do not require you to define all the fields explicitly. This allows for more flexibility, especially when dealing with large or evolving databases. You can add or remove fields in the database without needing to update the model every time.
  2. Easier Refactoring:

    • By keeping the schema in migrations, you can easily refactor your database structure without affecting your models. This makes it easier to maintain and evolve your application over time.

Fillable and Guarded Properties

  1. Mass Assignment Protection:
    • The $fillable and $guarded properties in Laravel models are used to protect against mass assignment vulnerabilities. They define which fields can be mass-assigned and which cannot. While they do not list all fields, they provide a layer of security and control over which fields can be updated via mass assignment.

Example

Here’s an example to illustrate the separation:

Migration File

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Model File

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasFactory;

    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

Conclusion

Laravel’s approach to separating the database schema (migrations) from the business logic (models) provides a clean, maintainable, and flexible architecture. While it may be different from frameworks like Django, it offers several advantages in terms of separation of concerns, flexibility, and maintainability. If you need to see all the fields, you can always refer to the migration files, which are designed to handle the database schema.

puklipo's avatar

Just avoiding boilerplate code.

A long time ago, I wrote getters and setters for every field. I don't want to write such useless code anymore.

anjanesh's avatar

@puklipo "I wrote getters and setters for every field" - I was still doing that for my non-framework based projects.

Please or to participate in this conversation.