Skip to main content

Overview

Dashboard Laravel uses Eloquent ORM for database interactions. Eloquent provides an elegant, simple ActiveRecord implementation for working with your database, where each database table has a corresponding “Model” used to interact with that table.

Available Models

The application includes the following Eloquent models:
  • App\Models\User - User authentication
  • App\Models\Cliente - Client/customer management
  • App\Models\Venta - Sales transactions
  • App\Models\Factura - Invoice management
  • App\Models\Mensaje - Client messaging
  • App\Models\Estadisticas - Analytics data
  • App\Models\Home - Homepage content
  • App\Models\Nosotros - About us information

Model Relationships

Cliente Model

The Cliente model demonstrates one-to-many relationships:
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Cliente extends Model
{
    use HasFactory;

    protected $fillable = [
        'nombre',
        'apellido',
        'email',
        'telefono',
        'estado',
        'segmento',
        'total_compras',
    ];

    // One-to-many: A client has many sales
    public function ventas()
    {
        return $this->hasMany(Venta::class);
    }

    // One-to-many: A client has many invoices
    public function facturas()
    {
        return $this->hasMany(Factura::class);
    }

    // One-to-many: A client has many messages
    public function mensajes()
    {
        return $this->hasMany(Mensaje::class);
    }
}

Venta Model

The Venta model shows both belongs-to and has-one relationships:
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Venta extends Model
{
    use HasFactory;

    protected $fillable = [
        'numero_orden',
        'cliente_id',
        'producto',
        'total',
        'estado',
    ];

    // Many-to-one: A sale belongs to a client
    public function cliente()
    {
        return $this->belongsTo(Cliente::class);
    }

    // One-to-one: A sale has one invoice
    public function factura()
    {
        return $this->hasOne(Factura::class);
    }
}

Factura Model

The Factura model with date casting:
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Factura extends Model
{
    use HasFactory;

    protected $fillable = [
        'numero_factura',
        'cliente_id',
        'venta_id',
        'concepto',
        'monto',
        'fecha_emision',
        'fecha_vencimiento',
        'estado',
    ];

    // Automatically cast dates
    protected $casts = [
        'fecha_emision'     => 'date',
        'fecha_vencimiento' => 'date',
    ];

    public function cliente()
    {
        return $this->belongsTo(Cliente::class);
    }

    public function venta()
    {
        return $this->belongsTo(Venta::class);
    }
}

Mensaje Model

The Mensaje model with boolean casting:
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Mensaje extends Model
{
    use HasFactory;

    protected $fillable = [
        'cliente_id',
        'contenido',
        'tipo',
        'leido',
    ];

    protected $casts = [
        'leido' => 'boolean',
    ];

    public function cliente()
    {
        return $this->belongsTo(Cliente::class);
    }
}

CRUD Operations

Creating Records

use App\Models\Cliente;

// Method 1: Create and save
$cliente = new Cliente();
$cliente->nombre = 'Juan';
$cliente->apellido = 'Pérez';
$cliente->email = '[email protected]';
$cliente->telefono = '555-0123';
$cliente->save();

// Method 2: Mass assignment
$cliente = Cliente::create([
    'nombre' => 'María',
    'apellido' => 'García',
    'email' => '[email protected]',
    'telefono' => '555-0124',
    'segmento' => 'premium',
]);

Reading Records

use App\Models\Cliente;

// Get all clients
$clientes = Cliente::all();

// Find by primary key
$cliente = Cliente::find(1);

// Find or fail (throws 404 if not found)
$cliente = Cliente::findOrFail(1);

// First matching record
$cliente = Cliente::where('email', '[email protected]')->first();

// Get premium clients
$premium = Cliente::where('segmento', 'premium')->get();

Updating Records

use App\Models\Cliente;

// Find and update
$cliente = Cliente::find(1);
$cliente->telefono = '555-9999';
$cliente->save();

// Update with mass assignment
$cliente = Cliente::find(1);
$cliente->update([
    'telefono' => '555-9999',
    'segmento' => 'premium',
]);

Deleting Records

use App\Models\Cliente;

// Find and delete
$cliente = Cliente::find(1);
$cliente->delete();

// Delete by ID
Cliente::destroy(1);

// Delete multiple by IDs
Cliente::destroy([1, 2, 3]);

Query Scopes

Create reusable query scopes in your models:
class Cliente extends Model
{
    // Local scope
    public function scopeActivo($query)
    {
        return $query->where('estado', 'activo');
    }

    public function scopePremium($query)
    {
        return $query->where('segmento', 'premium');
    }

    public function scopeConCompras($query, $minCompras = 1)
    {
        return $query->where('total_compras', '>=', $minCompras);
    }
}

// Usage
$clientes = Cliente::activo()->premium()->get();
$clientesActivos = Cliente::activo()->conCompras(5)->get();

Relationship Queries

Querying Relationships

use App\Models\Cliente;

// Clients who have sales
$clientesConVentas = Cliente::has('ventas')->get();

// Clients with at least 5 sales
$clientesActivos = Cliente::has('ventas', '>=', 5)->get();

// Clients with pending sales
$clientesPendientes = Cliente::whereHas('ventas', function ($query) {
    $query->where('estado', 'pendiente');
})->get();

// Clients without invoices
$sinFacturas = Cliente::doesntHave('facturas')->get();

Eager Loading

use App\Models\Cliente;

// Load relationships efficiently
$clientes = Cliente::with(['ventas', 'facturas'])->get();

// Conditional eager loading
$clientes = Cliente::with([
    'ventas' => function ($query) {
        $query->where('estado', 'completado');
    }
])->get();

// Lazy eager loading
$clientes = Cliente::all();
$clientes->load('ventas');

Accessors and Mutators

Add custom attributes to your models:
class Cliente extends Model
{
    // Accessor: get full name
    public function getNombreCompletoAttribute()
    {
        return "{$this->nombre} {$this->apellido}";
    }

    // Mutator: format email before saving
    public function setEmailAttribute($value)
    {
        $this->attributes['email'] = strtolower($value);
    }
}

// Usage
$cliente = Cliente::find(1);
echo $cliente->nombre_completo; // "Juan Pérez"

Model Events

Hook into model lifecycle events:
class Venta extends Model
{
    protected static function boot()
    {
        parent::boot();

        // Before creating a sale
        static::creating(function ($venta) {
            if (!$venta->numero_orden) {
                $venta->numero_orden = 'ORD-' . time();
            }
        });

        // After creating a sale
        static::created(function ($venta) {
            // Increment client's total purchases
            $venta->cliente->increment('total_compras');
        });
    }
}

Best Practices

  1. Use mass assignment protection - Always define $fillable or $guarded
  2. Eager load relationships - Avoid N+1 query problems with with()
  3. Use query scopes - Create reusable query logic
  4. Leverage relationship methods - Use create() on relationships instead of manual foreign key assignment
  5. Cast attributes - Define $casts for dates, booleans, JSON, etc.
  6. Use transactions - Wrap multiple operations in database transactions
  7. Index foreign keys - Ensure foreign key columns are indexed for performance

Build docs developers (and LLMs) love