PHPackages                             versaorm/versaorm-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. versaorm/versaorm-php

ActiveLibrary[Database &amp; ORM](/categories/database)

versaorm/versaorm-php
=====================

ORM ligero y seguro para PHP con motor PDO nativo - Query Builder fluido, Active Record simple, alto rendimiento

1.9.0(3mo ago)6116MITPHPPHP ^8.1CI passing

Since Aug 18Pushed 3mo agoCompare

[ Source](https://github.com/kriollo/versa-orm)[ Packagist](https://packagist.org/packages/versaorm/versaorm-php)[ Docs](https://github.com/kriollo/versa-orm)[ GitHub Sponsors](https://github.com/sponsors/kriollo)[ RSS](/packages/versaorm-versaorm-php/feed)WikiDiscussions main Synced today

READMEChangelog (10)Dependencies (12)Versions (22)Used By (0)

🚀 VersaORM-PHP
==============

[](#-versaorm-php)

**ORM sencillo y seguro para PHP – minimiza SQL manual y acelera tu desarrollo.**

[![CI](https://github.com/kriollo/versa-orm/actions/workflows/ci.yml/badge.svg)](https://github.com/kriollo/versa-orm/actions/workflows/ci.yml)[![Codecov](https://camo.githubusercontent.com/5460d4b981fd59963f8e024e36fb9d9fd3b787a9e25b82acfaf1b36c70e2ad17/68747470733a2f2f636f6465636f762e696f2f67682f6b72696f6c6c6f2f76657273612d6f726d2f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://codecov.io/gh/kriollo/versa-orm)[![Ask DeepWiki](https://camo.githubusercontent.com/0f5ae213ac378635adeb5d7f13cef055ad2f7d9a47b36de7b1c67dbe09f609ca/68747470733a2f2f6465657077696b692e636f6d2f62616467652e737667)](https://deepwiki.com/kriollo/versa-orm)[![Status](https://camo.githubusercontent.com/d6e6f3c53998470e14568ffca92b1e716677fb539b5bcf450f0a4900889f3ca9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374617475732d737461626c652d627269676874677265656e2e737667)](#)[![PHP](https://camo.githubusercontent.com/c0761d101b201f2531c8037e6264420e2e43705d3776a9fcfb70c8cf3d3563a3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d3737374242342e737667)](#)[![License](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](#)

- Última versión estable: 1.9.0
- Compatible con PHP 8.1+

[![VersaORM Logo](art/versaORMLogo.png)](art/versaORMLogo.png)

[](#)

> VersaORM-PHP está construido sobre **PDO nativo** para máxima compatibilidad, simplicidad y rendimiento. No requiere compilación externa: solo PHP + tu base de datos.

📚 Documentación Completa
------------------------

[](#-documentación-completa)

- 📖 **[Documentación Principal](docs/README.md)** - Guía completa desde básico hasta avanzado
- 🤖 **[Guía para IAs (llms.txt)](llms.txt)** - Mapa del repo y API clave para asistentes
- 🚀 **[Inicio Rápido](#-inicio-r%C3%A1pido)** - Empieza en 5 minutos
- ⚙️ **[Instalación](docs/02-instalacion/instalacion.md)** - Composer e instalación manual
- 🔧 **[CRUD Básico](docs/03-basico/crud-basico.md)** - Create, Read, Update, Delete
- 🔍 **[Query Builder](docs/04-query-builder/)** - Consultas fluidas y seguras
- 🔗 **[Relaciones](docs/05-relaciones/)** - hasMany, belongsTo, many-to-many
- 📖 **[Referencia SQL](docs/08-referencia-sql/)** - Equivalencias SQL ↔ VersaORM

### 🆕 Guías Especializadas (v1.8.6+)

[](#-guías-especializadas-v186)

- 🔧 **[Migración SchemaBuilder](docs/MigrationGuide_SchemaBuilder.md)** - De schemaCreate() al nuevo SchemaBuilder
- 🔗 **[Foreign Keys e Índices](docs/ForeignKeysAndIndexes_CompleteGuide.md)** - Guía completa con ejemplos prácticos
- 🐘 **[PostgreSQL SSL &amp; Pokio](docs/pokio-ssl-troubleshooting.md)** - Solución a errores de concurrencia y SSL (v1.8.4)
- ⚡ **[Tuning DB para Tests](docs/DatabaseTestTuning_MariaDB_PostgreSQL.md)** - Perfil rápido para MariaDB y PostgreSQL en entorno local

📋 ¿Qué es VersaORM?
-------------------

[](#-qué-es-versaorm)

VersaORM te permite interactuar con tu base de datos usando **objetos PHP** y un **Query Builder fluido**, apoyándose internamente en **PDO**. Así reduces errores, previenes inyecciones SQL y escribes código expresivo.

### 🤔 ¿Qué es un ORM?

[](#-qué-es-un-orm)

Un **ORM** (Object-Relational Mapping) traduce tus objetos PHP a filas en la base de datos. En vez de escribir SQL como esto:

```
-- SQL tradicional (complicado y propenso a errores)
SELECT * FROM users WHERE status = 'active' AND age >= 18 ORDER BY created_at DESC;
INSERT INTO users (name, email, password) VALUES ('Juan', 'juan@email.com', 'hash...');
UPDATE users SET status = 'inactive' WHERE id = 1;
```

Con VersaORM escribes código PHP natural y seguro:

```
// Con VersaORM (fácil y seguro)
$users = $orm->table('users')
    ->where('status', '=', 'active')
    ->where('age', '>=', 18)
    ->orderBy('created_at', 'desc')
    ->getAll();

$user = VersaModel::dispense('users');
$user->name = 'Juan';
$user->email = 'juan@email.com';
$user->password = password_hash('mi_password', PASSWORD_DEFAULT);
$user->store();

$user->status = 'inactive';
$user->store(); // Actualización automática
```

### 🏆 ¿Por qué elegir VersaORM?

[](#-por-qué-elegir-versaorm)

NecesidadSin ORM (solo PDO)Con VersaORMSeguridadDebes escribir y parametrizar cada sentenciaParámetros preparados automáticamenteMantenimientoSQL repetido en muchos archivosLógica centralizada y fluidaCurva de aprendizajeConocer bien SQL + PDOAPI consistente (where, join, order, etc.)RefactorsBuscar/editar cadenas SQLCambias métodos encadenadosErrores típicosInyección, comas, orden de placeholdersMinimizado por API tipada### 🌟 Características Principales

[](#-características-principales)

- ✅ **Construido sobre PDO** - Sin dependencias complicadas
- 🛡️ **Seguridad por defecto** - Prepared statements automáticos
- 🧩 **Modelos Active Record** - `dispense`, `load`, `store`, `trash`
- 🔍 **Query Builder fluido** - `where`, `join`, `groupBy`, `having`, `orderBy`, `limit`
- 🧠 **JOINs avanzados** - Condiciones encadenadas con `on()` y `onRaw()`
- 🔗 **Relaciones** - hasMany, belongsTo, many-to-many
- ⏰ **Timestamps automáticos** - `created_at` y `updated_at` con valores por defecto (Fix v1.4.1)
- 🏗️ **SchemaBuilder moderno** - API fluida para DDL con migración desde arrays
- 🔑 **Foreign Keys flexibles** - Sintaxis `foreign(['campo'])` y `foreign('campo')` validadas
- 💾 **Conversión de tipos avanzada** - Fechas, booleanos, JSON y **auto-inferencia de tipos** (v1.8.4)
- 🔀 **Operaciones de conjuntos** - UNION, INTERSECT, EXCEPT y **Full Outer Join emulado** (v1.8.4)
- 🔍 **Depuración de consultas** - Inspección con `toSql()` y `getBindings()` (v1.8.6)
- 🚫 **Cero compilación** - Solo PHP puro
- 📦 **Batch simple de modelos** - `VersaModel::storeAll([$m1,$m2])` devuelve array de IDs
- ⚡ **Soporte Pokio (Async/Fork)** - Preparado para concurrencia segura con PostgreSQL y SSL (v1.8.4)

✨ Arquitectura
--------------

[](#-arquitectura)

```
┌──────────────────────────┐
│        Tu Código         │
│  (Modelos + Consultas)   │
└────────────┬────────────┘
             │ API PHP
┌────────────▼────────────┐
│       VersaORM-PHP       │
│ - VersaORM.php           │
│ - VersaModel.php         │
│ - QueryBuilder.php       │
└────────────┬────────────┘
             │ PDO
┌────────────▼────────────┐
│     Base de Datos        │
│ MySQL | PostgreSQL | SQLite │
└──────────────────────────┘

```

**Simple y directo**: Todo fluye a través de PDO sin procesos externos.

🛠️ Instalación
--------------

[](#️-instalación)

### Via Composer (Recomendado)

[](#via-composer-recomendado)

```
composer require versaorm/versaorm-php
```

### Instalación Manual

[](#instalación-manual)

1. Descarga o clona el repositorio: ```
    git clone https://github.com/kriollo/versa-orm.git
    ```
2. Incluye los archivos necesarios: ```
    require_once 'src/VersaORM.php';
    require_once 'src/VersaModel.php';
    require_once 'src/QueryBuilder.php';
    ```

### Requisitos del Sistema

[](#requisitos-del-sistema)

- **PHP**: 8.1 o superior
- **Extensiones**: PDO, json, mbstring
- **Base de datos**: MySQL 5.7+, PostgreSQL 10+, o SQLite 3.6+
- **Sistema operativo**: Windows, Linux, macOS

**📖 Guía detallada**: [Instalación paso a paso](docs/02-instalacion/instalacion.md)

⚡ Inicio Rápido
---------------

[](#-inicio-rápido)

### 1. Instalación

[](#1-instalación)

```
# Via Composer (recomendado)
composer require versaorm/versaorm-php

# O descarga manual desde GitHub
```

### 2. Configuración Básica

[](#2-configuración-básica)

```
use VersaORM\VersaORM;
use VersaORM\VersaModel;

// Configurar la conexión
$orm = new VersaORM([
    'driver' => 'mysql',
    'host' => 'localhost',
    'database' => 'mi_app',
    'username' => 'usuario',
    'password' => 'password',
    'charset' => 'utf8mb4'
]);

// Configurar modelos
VersaModel::setORM($orm);
```

### 3. Tu Primer Ejemplo

[](#3-tu-primer-ejemplo)

```
// Crear un usuario
$user = VersaModel::dispense('users');
$user->name = 'Juan Pérez';
$user->email = 'juan@example.com';
$user->store(); // Se guarda automáticamente con timestamps

// Buscar usuarios activos
$activeUsers = $orm->table('users')
    ->where('status', '=', 'active')
    ->orderBy('created_at', 'desc')
    ->limit(10)
    ->getAll();

echo "Usuario creado con ID: " . $user->id;
echo "Usuarios activos encontrados: " . count($activeUsers);

// ✨ SchemaBuilder moderno (v1.4.1+)
use VersaORM\Schema\VersaSchema;

VersaSchema::create('documents', function ($table) {
    $table->id();
    $table->string('title');
    $table->timestamps(); // ✅ Valores automáticos funcionando

    // Foreign key con sintaxis flexible
    $table->foreign(['user_id'])->references('id')->on('users');
});
```

**¿Quieres más ejemplos?** → [Ver documentación completa](docs/README.md)

### 4. Ejemplos Comparativos (SQL vs VersaORM)

[](#4-ejemplos-comparativos-sql-vs-versaorm)

#### CRUD Básico - SQL vs VersaORM

[](#crud-básico---sql-vs-versaorm)

```
// ❌ SQL Manual (PDO) - Más código, más errores
$stmt = $pdo->prepare("INSERT INTO users (name,email) VALUES (?,?)");
$stmt->execute(['Juan Pérez','juan@example.com']);
$id = $pdo->lastInsertId();

$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
$userData = $stmt->fetch(PDO::FETCH_ASSOC);

// ✅ VersaORM - Simple y seguro
$user = VersaModel::dispense('users');
$user->name  = 'Juan Pérez';
$user->email = 'juan@example.com';
$user->store(); // ID asignado automáticamente

// Leer, actualizar y eliminar
$user = VersaModel::load('users', $user->id);
$user->email = 'nuevo@example.com';
$user->store(); // Actualización automática
$user->trash(); // Eliminación segura
```

#### Query Builder - Consultas Fluidas y Seguras

[](#query-builder---consultas-fluidas-y-seguras)

```
// ❌ SQL Manual - Propenso a errores de sintaxis
$sql = "SELECT * FROM users WHERE status = ? AND age >= ? AND role IN (?,?) ORDER BY created_at DESC LIMIT 10";
$stmt = $pdo->prepare($sql);
$stmt->execute(['active', 18, 'admin', 'editor']);
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

// ✅ VersaORM - Fluido y legible
$activeUsers = $orm->table('users')
    ->where('status', '=', 'active')
    ->where('age', '>=', 18)
    ->whereIn('role', ['admin', 'editor'])
    ->orderBy('created_at', 'desc')
    ->limit(10)
    ->getAll();

// Joins complejos simplificados
$userStats = $orm->table('users')
    ->select(['users.name', 'COUNT(posts.id) as total_posts'])
    ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
    ->where('users.status', '=', 'active')
    ->groupBy(['users.id', 'users.name'])
    ->having('total_posts', '>', 5)
    ->getAll();

// Operaciones masivas seguras
    ->where('stock', '>', 0)
    ->update(['status' => 'available']);

// Inspección de SQL generado (v1.8.6)
$sql = $orm->table('users')->where('id', '>', 10)->toSql();
$params = $orm->table('users')->where('id', '>', 10)->getBindings();
// $sql = "SELECT * FROM users WHERE id > ?"
// $params = [10]
```

#### 🔗 Joins Compuestos (Nuevo patrón sencillo)

[](#-joins-compuestos-nuevo-patrón-sencillo)

Necesitas unir por más de una columna? Usa el encadenado `join()->on()->on()` para mantenerlo claro:

```
$rows = $orm->table('orders AS o')
    ->join('invoices AS i')
    ->on('o.id','=','i.order_id')
    ->on('o.company_id','=','i.company_id')
    ->where('i.status','=','paid')
    ->getAll();

// Con mezcla AND / OR
$sessions = $orm->table('sessions AS s')
    ->join('users AS u')
    ->on('s.user_id','=','u.id')
    ->on('s.admin_id','=','u.id','OR')
    ->getAll();
```

Regla simple: lo que define el emparejamiento va en `on()`, lo que filtra el resultado final va en `where()`.

#### Operaciones CRUD Avanzadas

[](#operaciones-crud-avanzadas)

```
// UPSERT: Insertar si no existe, actualizar si existe
$result = $orm->table('products')->upsert(
    [
        'sku' => 'LAPTOP-001',
        'name' => 'MacBook Pro 16"',
        'price' => 2499.99,
        'stock' => 25
    ],
    ['sku'], // Claves únicas para detectar duplicados
    ['name', 'price', 'stock'] // Campos a actualizar si existe
);

// Método save() inteligente - detecta automáticamente INSERT vs UPDATE
$user = $orm->table('users')->save([
    'email' => 'john@example.com',
    'name' => 'John Updated',
    'role' => 'admin'
], ['email']); // Si existe el email, actualiza; si no, inserta

// insertOrUpdate() - alias intuitivo para upsert
$setting = $orm->table('settings')->insertOrUpdate([
    'key' => 'app_version',
    'value' => '2.1.0',
    'updated_at' => date('Y-m-d H:i:s')
], ['key']);

// replaceInto() - reemplazo completo (solo MySQL)
$backup = $orm->table('user_backups')->replaceInto([
    'user_id' => 123,
    'backup_data' => json_encode($userData),
    'created_at' => date('Y-m-d H:i:s')
]);
```

#### Modelos con Validación

[](#modelos-con-validación)

```
class User extends BaseModel {
    protected string $table = 'users';

    // Protección Mass Assignment
    protected array $fillable = ['name', 'email'];

    // Validación automática
    protected array $rules = [
        'name' => ['required', 'min:2'],
        'email' => ['required', 'email']
    ];
}

// Uso seguro con validación
try {
    $user = new User();
    $user->fill($_POST); // Solo campos $fillable
    $user->store(); // Validación automática
    echo "Usuario creado exitosamente";
} catch (VersaORMException $e) {
    echo "Error: " . $e->getMessage();
}
```

🔧 Configuración Rápida
----------------------

[](#-configuración-rápida)

### Configuración Básica

[](#configuración-básica)

```
use VersaORM\VersaORM;
use VersaORM\VersaModel;

$orm = new VersaORM([
    'driver' => 'mysql',        // mysql, postgresql, sqlite (alias aceptados: mariadb, pgsql, postgres)
    'host' => 'localhost',
    'database' => 'mi_app',
    'username' => 'usuario',
    'password' => 'password',
    'charset' => 'utf8mb4'
]);

VersaModel::setORM($orm);
```

### Configuraciones por Base de Datos

[](#configuraciones-por-base-de-datos)

#### Drivers soportados y alias

[](#drivers-soportados-y-alias)

VersaORM reconoce estos drivers principales:

- `mysql` (alias: `mariadb`)
- `postgresql` (alias: `pgsql`, `postgres`)
- `sqlite`

Se recomienda usar los nombres canónicos (`mysql`, `postgresql`, `sqlite`). Los alias se mantienen por compatibilidad.

**MySQL/MariaDB:**

```
$config = [
    'driver' => 'mysql',
    'host' => 'localhost',
    'port' => 3306,
    'database' => 'mi_app',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8mb4'
];
```

**PostgreSQL:**

```
$config = [
    'driver' => 'postgresql', // alias aceptados: pgsql, postgres
    'host' => 'localhost',
    'port' => 5432,
    'database' => 'mi_app',
    'username' => 'postgres',
    'password' => 'password'
];
```

**SQLite:**

```
$config = [
    'driver' => 'sqlite',
    'database' => 'database/app.sqlite'
];
```

Nota sobre persistencia: `store()` siempre devuelve el ID (int|string) del registro insertado/actualizado. Puedes capturarlo:

```
$id = $user->store(); // Inserta y devuelve ID
$user->name = 'Nuevo';
$sameId = $user->store(); // Devuelve el mismo ID tras update
```

**📖 Configuración detallada**: [Ver guía completa](docs/02-instalacion/configuracion.md)

📁 Estructura del Proyecto
-------------------------

[](#-estructura-del-proyecto)

```
versaORM-PHP/
├── src/                    # Código fuente VersaORM
│   ├── VersaORM.php       # Clase principal ORM
│   ├── VersaModel.php     # Modelos Active Record
│   ├── QueryBuilder.php   # Constructor de consultas
│   ├── Relations/         # Sistema de relaciones
│   ├── SQL/              # Generadores SQL específicos
│   └── Traits/           # Funcionalidades reutilizables
├── docs/                  # Documentación completa
│   ├── 01-introduccion/   # Conceptos básicos
│   ├── 02-instalacion/    # Guías de instalación
│   ├── 03-basico/         # CRUD y fundamentos
│   ├── 04-query-builder/  # Constructor de consultas
│   ├── 05-relaciones/     # Relaciones entre modelos
│   ├── 06-avanzado/       # Funcionalidades avanzadas
│   ├── 07-seguridad-tipado/ # Seguridad y validación
│   └── 08-referencia-sql/ # Equivalencias SQL
├── example/               # Aplicación de ejemplo
├── tests/                 # Suite de pruebas
├── composer.json         # Configuración Composer
└── README.md            # Esta documentación

```

🏆 Mejores Prácticas Demostradas
-------------------------------

[](#-mejores-prácticas-demostradas)

### 1. Usar Métodos ORM para Operaciones Básicas

[](#1-usar-métodos-orm-para-operaciones-básicas)

```
// ✅ CORRECTO - Usar métodos ORM
$task = VersaModel::dispense('tasks');
$task->title = 'Nueva tarea';
$task->store();

// ❌ INCORRECTO - SQL innecesario para operaciones simples
$orm->exec("INSERT INTO tasks (title) VALUES (?)", ['Nueva tarea']);
```

### 2. exec() Solo para Consultas Complejas

[](#2-exec-solo-para-consultas-complejas)

```
// ✅ CORRECTO - Consulta compleja que necesita SQL
$stats = $orm->exec("SELECT COUNT(*) as total, AVG(rating) as avg_rating FROM tasks");

// ❌ INCORRECTO - Operación simple con SQL
$task = $orm->exec("SELECT * FROM tasks WHERE id = ?", [1])[0];
// MEJOR:
$task = VersaModel::load('tasks', 1);
```

### 3. Manejo de Errores Apropiado

[](#3-manejo-de-errores-apropiado)

```
try {
    $task = VersaModel::dispense('tasks');
    $task->title = $title;
    $task->store();
    echo "✅ Tarea creada exitosamente";
} catch (VersaORMException $e) {
    echo "❌ Error: " . $e->getMessage();
}
```

### 4. 🔒 Modo Freeze para Protección de Esquema

[](#4--modo-freeze-para-protección-de-esquema)

```
// ✅ PRODUCCIÓN - Activar freeze para proteger esquema
if (app()->environment('production')) {
    $orm->freeze(true);
    echo "🔒 Esquema protegido contra modificaciones DDL";
}

// ✅ DESARROLLO - Freeze selectivo por modelo
$orm->freezeModel(CriticalTable::class, true);

// ❌ BLOQUEADO - En modo freeze esto lanza excepción
try {
    $orm->exec("CREATE TABLE test (id INT)");
} catch (VersaORMException $e) {
    if ($e->getCode() === 'FREEZE_VIOLATION') {
        echo "Operación DDL bloqueada por seguridad";
    }
}
```

🚨 Troubleshooting
-----------------

[](#-troubleshooting)

### Error de conexión a la base de datos

[](#error-de-conexión-a-la-base-de-datos)

- Verifica las credenciales en la configuración
- Asegúrate de que el servidor de base de datos esté ejecutándose
- Confirma que la base de datos existe o que el usuario tiene permisos para crearla
- Revisa que las extensiones PDO necesarias estén instaladas

### Errores comunes

[](#errores-comunes)

- **Class not found**: Verifica que el autoloader esté incluido correctamente
- **PDO extension not found**: Instala la extensión PDO para tu base de datos
- **Permission denied**: Verifica permisos de escritura para SQLite
- **Connection refused**: Confirma host y puerto de la base de datos

**📖 Guía completa de troubleshooting**: [Manejo de errores](docs/03-basico/manejo-errores.md)

📚 Documentación Detallada
-------------------------

[](#-documentación-detallada)

### 🎯 Por Nivel de Experiencia

[](#-por-nivel-de-experiencia)

- **👶 Principiante**: [Introducción](docs/01-introduccion/) → [Instalación](docs/02-instalacion/) → [CRUD Básico](docs/03-basico/)
- **🏃 Intermedio**: [Query Builder](docs/04-query-builder/) → [Relaciones](docs/05-relaciones/) → [Avanzado](docs/06-avanzado/)
- **🚀 Experto**: [Seguridad](docs/07-seguridad-tipado/) → [Referencia SQL](docs/08-referencia-sql/)

### 📖 Por Tema

[](#-por-tema)

- **[🔧 CRUD y Modelos](docs/03-basico/)** - dispense, load, store, trash
- **[🔍 Query Builder](docs/04-query-builder/)** - Consultas fluidas y seguras
- **[🔗 Relaciones](docs/05-relaciones/)** - hasMany, belongsTo, many-to-many
- **[🚀 Funciones Avanzadas](docs/06-avanzado/)** - Batch, UPSERT, transacciones
- **[🔒 Seguridad](docs/07-seguridad-tipado/)** - Validación, freeze mode, tipado
- **[📖 Referencia SQL](docs/08-referencia-sql/)** - Equivalencias SQL ↔ VersaORM

### 🛠️ Para Desarrolladores

[](#️-para-desarrolladores)

- **[🧪 Aplicación de Ejemplo](example/README.md)** - Demo completa funcional
- **[🏗️ Contribuir](CONTRIBUTING.md)** - Guía para contribuir al proyecto

🌟 Características Destacadas
----------------------------

[](#-características-destacadas)

### ⚡ Alto Rendimiento

[](#-alto-rendimiento)

- **PDO optimizado** con prepared statements reutilizables
- **API fluida** que reduce código repetitivo y errores
- **Query Builder eficiente** con generación SQL optimizada
- **Lazy loading** para relaciones bajo demanda

### 🛡️ Seguridad Robusta

[](#️-seguridad-robusta)

- **Prepared statements automáticos** - Protección contra SQL injection
- **Mass Assignment protection** - Control con `$fillable` / `$guarded`
- **Validación declarativa** - Reglas por modelo automáticas
- **Freeze mode** - Bloquea cambios accidentales de esquema en producción

### 🚀 Desarrollo Ágil

[](#-desarrollo-ágil)

- **Creación automática de campos** - Desarrollo rápido sin DDL manual
- **Detección inteligente de tipos** - Mapeo automático PHP ↔ SQL
- **Modo development** - Prototipado rápido sin esquemas previos
- **Transición suave** - De desarrollo (freeze OFF) a producción (freeze ON)

### 🔄 Máxima Compatibilidad

[](#-máxima-compatibilidad)

- **Múltiples bases de datos** - MySQL, PostgreSQL, SQLite
- **Framework agnostic** - Integra con cualquier proyecto PHP
- **Estándares PSR** - Sigue las mejores prácticas de PHP

🤝 Contribuir
------------

[](#-contribuir)

¡Las contribuciones son bienvenidas! Por favor:

1. Fork el repositorio
2. Crea una rama para tu feature (`git checkout -b feature/nueva-funcionalidad`)
3. Commit tus cambios (`git commit -m 'Agregar nueva funcionalidad'`)
4. Push a la rama (`git push origin feature/nueva-funcionalidad`)
5. Abre un Pull Request

### Reportar Bugs

[](#reportar-bugs)

- Usa el [Issue Tracker](https://github.com/kriollo/versa-orm/issues)
- Incluye detalles del entorno (PHP version, OS, DB)
- Proporciona pasos para reproducir el problema

📄 Licencia
----------

[](#-licencia)

MIT License - ver archivo [LICENSE](LICENSE) para detalles.

💬 Soporte
---------

[](#-soporte)

- **Documentación**: [docs/](docs/)
- **Issues**: [GitHub Issues](https://github.com/kriollo/versa-orm/issues)
- **Discusiones**: [GitHub Discussions](https://github.com/kriollo/versa-orm/discussions)
- **Email**:

---

�️ SQL vs VersaORM (Cheat Sheet Rápido)
---------------------------------------

[](#️-sql-vs-versaorm-cheat-sheet-rápido)

ObjetivoSQLVersaORMInsert`INSERT INTO users (name) VALUES (?)``$u=VersaModel::dispense('users');$u->name='Ana';$u->store();`Select por ID`SELECT * FROM users WHERE id=?``$u=VersaModel::load('users',1);`Filtro múltiple`... WHERE status='a' AND age>=18``$orm->table('users')->where('status','=','a')->where('age','>=',18)->getAll();`Orden + Límite`ORDER BY created_at DESC LIMIT 10``->orderBy('created_at','desc')->limit(10)`Join simple`SELECT u.*,p.bio FROM users u JOIN profiles p ON p.user_id=u.id``$orm->table('users')->join('profiles','users.id','=','profiles.user_id')->select(['users.*','profiles.bio'])->getAll();`Agregación`SELECT status,COUNT(*) c FROM users GROUP BY status``$orm->table('users')->select(['status','COUNT(*) c'])->groupBy('status')->getAll();`Delete cond.`DELETE FROM sessions WHERE last_seen < ?``$orm->table('sessions')->where('last_seen','
