# Models: BaseModel Inheritance

## Overview

**Every model in the system MUST inherit from `BaseModel`** instead of Laravel's default `Illuminate\Database\Eloquent\Model`. This is a critical requirement for maintaining consistency and enabling core functionality.

## The Rule

```php
// ❌ WRONG - Never do this
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    // ...
}

// ✅ CORRECT - Always do this
use App\Models\BaseModel;

class Product extends BaseModel
{
    // ...
}
```

## What BaseModel Provides

### 1. UUID Primary Keys

```php
// BaseModel automatically handles UUID generation
// No need to manually set IDs

$product = Product::create([
    'name' => 'Widget',
    'price' => 99.99
]);

echo $product->id; // "550e8400-e29b-41d4-a716-446655440000"
```

### 2. Company Association

```php
// BaseModel automatically sets company_id on creation
// Based on authenticated user's company

$product = Product::create(['name' => 'Widget']);
echo $product->company_id; // Automatically set
```

### 3. Standard Traits

BaseModel includes essential traits:

| Trait | Purpose |
|-------|---------|
| `HasUuids` | UUID primary key handling |
| `CompanyScope` | Automatic company filtering |
| `SoftDeletes` | Soft deletion support |

### 4. Common Relationships

```php
// Every model has access to company relationship
$product->company; // Returns associated Company model
```

## BaseModel Structure

```php
<?php

namespace App\Models;

use App\Scopes\CompanyScope;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class BaseModel extends Model
{
    use HasUuids;
    use SoftDeletes;

    /**
     * Boot the model.
     */
    protected static function boot()
    {
        parent::boot();

        // Add CompanyScope globally
        static::addGlobalScope(new CompanyScope);

        // Auto-set company_id on creation
        static::creating(function ($model) {
            if (auth()->check() && !$model->company_id) {
                $model->company_id = auth()->user()->company_id;
            }
        });
    }

    /**
     * Get the company that owns this model.
     */
    public function company()
    {
        return $this->belongsTo(Company::class);
    }
}
```

## Model Template

Use this template when creating new models:

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class NewFeature extends BaseModel
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<string>
     */
    protected $fillable = [
        'company_id',
        'name',
        'description',
        'status',
        // Add other fields...
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'is_active' => 'boolean',
        'metadata' => 'array',
        'amount' => 'decimal:2',
        'date' => 'date',
    ];

    /*
    |--------------------------------------------------------------------------
    | Relationships
    |--------------------------------------------------------------------------
    */

    public function relatedModel(): BelongsTo
    {
        return $this->belongsTo(RelatedModel::class);
    }

    public function items(): HasMany
    {
        return $this->hasMany(NewFeatureItem::class);
    }

    /*
    |--------------------------------------------------------------------------
    | Accessors & Mutators
    |--------------------------------------------------------------------------
    */

    // Add as needed...

    /*
    |--------------------------------------------------------------------------
    | Scopes
    |--------------------------------------------------------------------------
    */

    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    /*
    |--------------------------------------------------------------------------
    | Methods
    |--------------------------------------------------------------------------
    */

    // Add business logic methods...
}
```

## Required Properties

### Fillable Array

Always define `$fillable` with all mass-assignable attributes:

```php
protected $fillable = [
    'company_id',      // Always include
    'name',
    'description',
    // ... other fields
];
```

### Casts Array

Define proper type casting for attributes:

```php
protected $casts = [
    'is_active' => 'boolean',
    'amount' => 'decimal:2',
    'quantity' => 'integer',
    'metadata' => 'array',
    'date' => 'date',
    'datetime' => 'datetime',
];
```

## Common Mistakes to Avoid

### 1. Forgetting company_id in Fillable

```php
// ❌ WRONG
protected $fillable = ['name', 'description'];

// ✅ CORRECT
protected $fillable = ['company_id', 'name', 'description'];
```

### 2. Using Guarded Instead of Fillable

```php
// ❌ AVOID - Less explicit
protected $guarded = [];

// ✅ PREFERRED - Explicit field listing
protected $fillable = ['company_id', 'name', 'description'];
```

### 3. Not Using Type Casting

```php
// ❌ WRONG - No casting
class Product extends BaseModel
{
    protected $fillable = ['price', 'is_active'];
}

// ✅ CORRECT - Proper casting
class Product extends BaseModel
{
    protected $fillable = ['price', 'is_active'];

    protected $casts = [
        'price' => 'decimal:2',
        'is_active' => 'boolean',
    ];
}
```

## Migration Requirements

When creating migrations for models that extend BaseModel:

```php
Schema::create('new_features', function (Blueprint $table) {
    $table->uuid('id')->primary();
    $table->foreignUuid('company_id')->constrained()->cascadeOnDelete();

    // Your feature-specific columns...
    $table->string('name');
    $table->text('description')->nullable();
    $table->boolean('is_active')->default(true);

    $table->timestamps();
    $table->softDeletes();

    // Indexes
    $table->index('company_id');
});
```

## Verification Checklist

Before committing a new model, verify:

- [ ] Model extends `BaseModel`, not `Model`
- [ ] `company_id` is in the `$fillable` array
- [ ] All attributes have appropriate `$casts`
- [ ] Migration includes `uuid('id')->primary()`
- [ ] Migration includes `foreignUuid('company_id')`
- [ ] Migration includes `softDeletes()`
- [ ] Relationships are properly typed with return types

## Related Documentation

- [02-scopes.md](02-scopes.md) - CompanyScope implementation
- [05-complete-checklist.md](05-complete-checklist.md) - Full development checklist
