{"id":35133333,"url":"https://github.com/mongoose-studio/phobos-framework-database","last_synced_at":"2026-01-31T05:00:44.107Z","repository":{"id":318725205,"uuid":"1074121768","full_name":"mongoose-studio/phobos-framework-database","owner":"mongoose-studio","description":"Capa de base de datos para PhobosFramework con Query Builder expresivo, Active Record, transacciones anidadas y schema aliasing. PHP 8.3+.","archived":false,"fork":false,"pushed_at":"2026-01-19T02:51:55.000Z","size":129,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-19T08:38:35.823Z","etag":null,"topics":["database-layer","orm-framework","phobos-framework"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mongoose-studio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-11T07:22:31.000Z","updated_at":"2026-01-19T02:51:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"532700e5-f6bd-4aaa-a0d0-16acce18f83b","html_url":"https://github.com/mongoose-studio/phobos-framework-database","commit_stats":null,"previous_names":["mongoose-studio/phobos-framework-database"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/mongoose-studio/phobos-framework-database","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoose-studio%2Fphobos-framework-database","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoose-studio%2Fphobos-framework-database/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoose-studio%2Fphobos-framework-database/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoose-studio%2Fphobos-framework-database/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mongoose-studio","download_url":"https://codeload.github.com/mongoose-studio/phobos-framework-database/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mongoose-studio%2Fphobos-framework-database/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28929862,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T04:05:25.756Z","status":"ssl_error","status_checked_at":"2026-01-31T04:02:35.005Z","response_time":128,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database-layer","orm-framework","phobos-framework"],"created_at":"2025-12-28T07:34:20.938Z","updated_at":"2026-01-31T05:00:44.090Z","avatar_url":"https://github.com/mongoose-studio.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Phobos Database Layer\n\n[![PHP Version](https://img.shields.io/badge/PHP-%3E%3D%208.3-blue)](https://www.php.net/)\n[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE.txt)\n[![Phobos Framework](https://img.shields.io/badge/Phobos-Framework-orange)](https://github.com/mongoose-studio/phobos-framework)\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/mongoose-studio/phobos-framework/main/phobos-banner-dark.png\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/mongoose-studio/phobos-framework/main/phobos-banner.png\"\u003e\n  \u003cimg alt=\"Phobos Framework\" height=\"64px\" src=\"https://raw.githubusercontent.com/mongoose-studio/phobos-framework/main/phobos-banner-dark.png\"\u003e\n\u003c/picture\u003e\n\nLa capa de base de datos de **Phobos Framework** está diseñada como un componente standalone pensado para integrarse pero no depender del core (a excepción del `DatabaseServiceProvider`). Viene con un constructor de consultas encadenadas que hace las consultas más legibles y un **ORM** estilo **Active Record** para definir y trabajar con modelos de forma directa. Soporta múltiples conexiones simultáneas, transacciones anidadas y adaptadores personalizados, lo que te permite ajustar comportamiento y rendimiento según el caso.\n\nEntre sus virtudes están el soporte para múltiples conexiones simultáneas, transacciones anidadas y la posibilidad de agregar adaptadores personalizados (si necesitas un driver especial o comportamiento distinto). En pocas palabras: te da control y rendimiento cuando lo necesitas, pero sin sacrificar legibilidad ni flexibilidad arquitectónica.\n\n## Características\n\n- 🔍 **Query Builder Fluido** - Interfaz expresiva para SELECT, INSERT, UPDATE, DELETE\n- 🏗️ **ORM con Active Record** - Entidades que combinan datos y operaciones de BD\n- 🔄 **Gestión de Transacciones** - Soporte para transacciones anidadas con savepoints\n- 🎯 **Change Tracking** - Las entidades rastrean cambios para optimizar UPDATEs\n- 🔌 **Múltiples Conexiones** - Manejo de múltiples bases de datos simultáneamente\n- 🗂️ **Schema Aliasing** - Mapeo de aliases para multi-tenant o multi-ambiente\n- 🛡️ **Prepared Statements** - Todas las queries usan parameter binding para seguridad\n- 💉 **Integración con DI** - Compatible con el Container de Phobos Framework\n\n## Instalación\n\n```bash\ncomposer require mongoose-studio/phobos-database\n```\n\n## Configuración\n\n### 1. Configuración de Base de Datos\n\nCrea `config/database.php`:\n\n```php\n\u003c?php\n\nreturn [\n    'default' =\u003e 'mysql',\n    \n    'drivers' =\u003e [\n        'mysql' =\u003e PhobosFramework\\Database\\Drivers\\MySQLDriver::class,\n        'pgsql' =\u003e PhobosFramework\\Database\\Drivers\\PostgreSQLDriver::class,\n    ],\n    \n    'connections' =\u003e [\n        'mysql' =\u003e [\n            'driver' =\u003e 'mysql',\n            'host' =\u003e env('DB_HOST', 'localhost'),\n            'port' =\u003e env('DB_PORT', '3306'),\n            'database' =\u003e env('DB_DATABASE', 'myapp'),\n            'username' =\u003e env('DB_USERNAME', 'root'),\n            'password' =\u003e env('DB_PASSWORD', ''),\n            'charset' =\u003e 'utf8mb4',\n            'collation' =\u003e 'utf8mb4_unicode_ci',\n        ],\n        \n        'analytics' =\u003e [\n            'driver' =\u003e 'mysql',\n            'host' =\u003e env('ANALYTICS_DB_HOST', 'localhost'),\n            'database' =\u003e env('ANALYTICS_DB_DATABASE', 'analytics'),\n            'username' =\u003e env('ANALYTICS_DB_USERNAME', 'root'),\n            'password' =\u003e env('ANALYTICS_DB_PASSWORD', ''),\n        ],\n    ],\n];\n```\n\n### 2. Registro del Service Provider (con Phobos Framework)\n\n```php\n\u003c?php\n\nnamespace App;\n\nuse PhobosFramework\\Database\\DatabaseServiceProvider;\n\nclass AppModule implements ModuleInterface\n{\n    public function providers(): array\n    {\n        return [\n            DatabaseServiceProvider::class,\n            // ... otros providers\n        ];\n    }\n}\n```\n\n### 3. Schema Aliasing (Opcional)\n\nPara ambientes multi-tenant o multi-entorno:\n\n```php\n// En bootstrap o service provider\nschemaAlias('app', 'myapp_production');\nschemaAlias('analytics', 'myapp_analytics');\n\n// O múltiples a la vez\nschemaBulkAlias([\n    'app' =\u003e 'myapp_production',\n    'analytics' =\u003e 'myapp_analytics',\n    'tenant1' =\u003e 'tenant_abc_2024',\n]);\n```\n\n## Uso\n\n### Query Builder\n\n#### SELECT Queries\n\n```php\n// Query simple\n$users = query()\n    -\u003eselect('id', 'username', 'email')\n    -\u003efrom('users')\n    -\u003ewhere(['active = ?' =\u003e 1])\n    -\u003efetch();\n\n// Con JOINs\n$posts = query()\n    -\u003eselect('p.id', 'p.title', 'u.username', 'u.email')\n    -\u003efrom('posts', 'p')\n    -\u003einnerJoin('users', 'u', 'u.id = p.user_id')\n    -\u003ewhere(['p.published = ?' =\u003e true])\n    -\u003eorderBy('p.created_at DESC')\n    -\u003elimit(10)\n    -\u003efetch();\n\n// Con múltiples condiciones\n$results = query()\n    -\u003eselect('*')\n    -\u003efrom('products')\n    -\u003ewhere(['category = ?' =\u003e 'electronics'])\n    -\u003ewhere(['price \u003e ?' =\u003e 100])\n    -\u003ewhere(['stock \u003e ?' =\u003e 0])\n    -\u003efetch();\n\n// LIKE y operadores\n$search = query()\n    -\u003eselect('*')\n    -\u003efrom('articles')\n    -\u003ewhere(['title LIKE ?' =\u003e '%PHP%'])\n    -\u003eorWhere(['content LIKE ?' =\u003e '%framework%'])\n    -\u003efetch();\n\n// Subqueries\n$subquery = query()\n    -\u003eselect('user_id')\n    -\u003efrom('orders')\n    -\u003ewhere(['total \u003e ?' =\u003e 1000]);\n\n$vipUsers = query()\n    -\u003eselect('*')\n    -\u003efrom('users')\n    -\u003ewhere(['id IN' =\u003e $subquery])\n    -\u003efetch();\n\n// GROUP BY y HAVING\n$stats = query()\n    -\u003eselect('category', 'COUNT(*) as total', 'AVG(price) as avg_price')\n    -\u003efrom('products')\n    -\u003egroupBy('category')\n    -\u003ehaving(['COUNT(*) \u003e ?' =\u003e 5])\n    -\u003efetch();\n\n// UNION\n$query1 = query()-\u003eselect('name')-\u003efrom('customers');\n$query2 = query()-\u003eselect('name')-\u003efrom('suppliers');\n\n$all = $query1-\u003eunion($query2)-\u003efetch();\n\n// Fetch único resultado\n$user = query()\n    -\u003eselect('*')\n    -\u003efrom('users')\n    -\u003ewhere(['id = ?' =\u003e 5])\n    -\u003efetchOne();\n\n// Fetch columna específica\n$emails = query()\n    -\u003eselect('email')\n    -\u003efrom('users')\n    -\u003efetchColumn('email');\n\n// Contar resultados\n$count = query()\n    -\u003eselect('COUNT(*) as total')\n    -\u003efrom('users')\n    -\u003ewhere(['active = ?' =\u003e 1])\n    -\u003efetchOne()['total'];\n```\n\n#### INSERT Queries\n\n```php\n// Insert simple\ninsert()\n    -\u003einto('users')\n    -\u003evalues([\n        'username' =\u003e 'john_doe',\n        'email' =\u003e 'john@example.com',\n        'created_at' =\u003e date('Y-m-d H:i:s'),\n    ])\n    -\u003eexecute();\n\n// Insert múltiple\ninsert()\n    -\u003einto('tags')\n    -\u003evalues([\n        ['name' =\u003e 'PHP'],\n        ['name' =\u003e 'JavaScript'],\n        ['name' =\u003e 'Python'],\n    ])\n    -\u003eexecute();\n\n// Con conexión específica\ninsert('analytics')\n    -\u003einto('events')\n    -\u003evalues(['event' =\u003e 'page_view', 'timestamp' =\u003e time()])\n    -\u003eexecute();\n```\n\n#### UPDATE Queries\n\n```php\n// Update simple\nupdate()\n    -\u003etable('users')\n    -\u003eset([\n        'email' =\u003e 'newemail@example.com',\n        'updated_at' =\u003e date('Y-m-d H:i:s'),\n    ])\n    -\u003ewhere(['id = ?' =\u003e 5])\n    -\u003eexecute();\n\n// Update con límite\nupdate()\n    -\u003etable('posts')\n    -\u003eset(['views' =\u003e 'views + 1']) // Expresión SQL\n    -\u003ewhere(['category = ?' =\u003e 'news'])\n    -\u003elimit(10)\n    -\u003eexecute();\n\n// Update múltiples condiciones\nupdate()\n    -\u003etable('products')\n    -\u003eset(['price' =\u003e 'price * 0.9']) // 10% descuento\n    -\u003ewhere(['category = ?' =\u003e 'electronics'])\n    -\u003ewhere(['stock \u003e ?' =\u003e 0])\n    -\u003eexecute();\n```\n\n#### DELETE Queries\n\n```php\n// Delete simple\ndelete()\n    -\u003efrom('sessions')\n    -\u003ewhere(['expires_at \u003c ?' =\u003e date('Y-m-d H:i:s')])\n    -\u003eexecute();\n\n// Delete con límite\ndelete()\n    -\u003efrom('logs')\n    -\u003ewhere(['level = ?' =\u003e 'debug'])\n    -\u003elimit(1000)\n    -\u003eexecute();\n\n// Delete con ORDER BY\ndelete()\n    -\u003efrom('notifications')\n    -\u003ewhere(['user_id = ?' =\u003e 123])\n    -\u003eorderBy('created_at ASC')\n    -\u003elimit(50)\n    -\u003eexecute();\n```\n\n### Entidades (Active Record)\n\n#### Definir una Entidad\n\n```php\n\u003c?php\n\nnamespace App\\Entities;\n\nuse PhobosFramework\\Database\\Entity\\TableEntity;\n\nclass User extends TableEntity\n{\n    // Configuración de la tabla\n    protected static string $schema = 'app';  // Alias del schema\n    protected static string $entity = 'users'; // Nombre de la tabla\n    protected static array $pk = ['id'];       // Primary key(s)\n    protected static ?string $connection = null; // null = default connection\n\n    // Propiedades (mapean a columnas)\n    public int $id;\n    public string $username;\n    public string $email;\n    public string $password;\n    public bool $active;\n    public ?string $created_at;\n    public ?string $updated_at;\n}\n```\n\n#### Operaciones CRUD\n\n**CREATE:**\n\n```php\n$user = new User();\n$user-\u003eusername = 'juan_perez';\n$user-\u003eemail = 'juanperez@ejemplo.cl';\n$user-\u003epassword = password_hash('secret', PASSWORD_BCRYPT);\n$user-\u003eactive = true;\n$user-\u003ecreated_at = date('Y-m-d H:i:s');\n\n$user-\u003esave(); // INSERT en la BD\necho $user-\u003eid; // ID auto-incrementado disponible\n```\n\n**READ:**\n\n```php\n// Buscar por primary key\n$user = User::findByPk(5);\n\n// Buscar múltiples registros\n$activeUsers = User::find(\n    ['active = ?' =\u003e true],\n    'username ASC',\n    0,\n    10\n);\n\n// Buscar primer resultado\n$admin = User::findFirst(['username = ?' =\u003e 'admin']);\n\n// Contar registros\n$totalUsers = User::count(['active = ?' =\u003e true]);\n\n// Verificar existencia\n$exists = User::exists(['email = ?' =\u003e 'test@example.com']);\n```\n\n**UPDATE:**\n\n```php\n$user = User::findByPk(5);\n$user-\u003eemail = 'newemail@example.com';\n$user-\u003eupdated_at = date('Y-m-d H:i:s');\n\n$user-\u003esave(); // UPDATE automático (solo campos modificados)\n\n// Verificar si hay cambios\nif ($user-\u003eisDirty()) {\n    $changes = $user-\u003egetDirtyFields(); // ['email', 'updated_at']\n}\n```\n\n**DELETE:**\n\n```php\n// Delete instancia\n$user = User::findByPk(5);\n$user-\u003eremove();\n\n// Delete estático\nUser::delete(['active = ?' =\u003e false], 100);\n```\n\n#### Change Tracking\n\n```php\n$user = User::findByPk(5);\n\n// Estado original\n$original = $user-\u003egetOriginalData();\n\n// Modificar\n$user-\u003eemail = 'new@example.com';\n$user-\u003eusername = 'new_username';\n\n// Verificar cambios\nif ($user-\u003eisDirty()) {\n    $dirty = $user-\u003egetDirtyFields(); // ['email', 'username']\n    \n    // Solo campos modificados en UPDATE\n    $changes = $user-\u003etoArray(true); // ['email' =\u003e 'new@...', 'username' =\u003e 'new_...']\n}\n\n$user-\u003esave(); // Solo actualiza campos modificados\n```\n\n#### Modo Dry-Run (Debug)\n\n```php\n// Ver SQL sin ejecutar\n$dryRun = User::find(['active = ?' =\u003e true], 'id ASC', 0, 10, true);\n// Returns: ['query' =\u003e 'SELECT ...', 'bindings' =\u003e [1]]\n\n$user = new User();\n$user-\u003eusername = 'test';\n$dryRun = $user-\u003esave(true);\n// Returns: ['query' =\u003e 'INSERT INTO ...', 'bindings' =\u003e ['test']]\n```\n\n### Entidades de Vista (Read-Only)\n\n```php\n\u003c?php\n\nnamespace App\\Entities;\n\nuse PhobosFramework\\Database\\Entity\\ViewEntity;\n\nclass UserStats extends ViewEntity\n{\n    protected static string $schema = 'app';\n    protected static string $entity = 'v_user_statistics';\n    \n    public int $user_id;\n    public string $username;\n    public int $total_posts;\n    public int $total_comments;\n    public float $avg_rating;\n}\n\n// Uso (solo lectura)\n$stats = UserStats::find();\n$userStat = UserStats::findFirst(['user_id = ?' =\u003e 5]);\n\n// save() y remove() lanzarán LogicException\n```\n\n### Stored Procedures\n\n```php\n\u003c?php\n\nnamespace App\\Entities;\n\nuse PhobosFramework\\Database\\Entity\\StoredProcedureEntity;\n\nclass GenerateReport extends StoredProcedureEntity\n{\n    protected static string $schema = 'app';\n    protected static string $entity = 'sp_generate_monthly_report';\n    \n    // Parámetros del SP\n    public int $month;\n    public int $year;\n    public string $report_type;\n}\n\n// Ejecutar\n$sp = new GenerateReport();\n$sp-\u003emonth = 10;\n$sp-\u003eyear = 2024;\n$sp-\u003ereport_type = 'sales';\n\n$results = $sp-\u003eexecute();\n```\n\n### Transacciones\n\n#### Transacciones Manuales\n\n```php\ntry {\n    beginTransaction();\n    \n    $user = new User();\n    $user-\u003eusername = 'john';\n    $user-\u003esave();\n    \n    $profile = new Profile();\n    $profile-\u003euser_id = $user-\u003eid;\n    $profile-\u003esave();\n    \n    commit();\n} catch (\\Exception $e) {\n    rollback();\n    throw $e;\n}\n```\n\n#### Transacciones con Helper\n\n```php\n$result = transaction(function() {\n    $user = new User();\n    $user-\u003eusername = 'john';\n    $user-\u003esave();\n    \n    $profile = new Profile();\n    $profile-\u003euser_id = $user-\u003eid;\n    $profile-\u003esave();\n    \n    return $user;\n});\n\n// Rollback automático si se lanza excepción\n```\n\n#### Transacciones Anidadas (Savepoints)\n\n```php\nbeginTransaction(); // Transacción real\n\ntry {\n    $user = new User();\n    $user-\u003esave();\n    \n    beginTransaction(); // Savepoint sp_1\n    \n    try {\n        $profile = new Profile();\n        $profile-\u003euser_id = $user-\u003eid;\n        $profile-\u003esave();\n        \n        commit('sp_1'); // Commit savepoint\n    } catch (\\Exception $e) {\n        rollback('sp_1'); // Rollback solo el savepoint\n    }\n    \n    commit(); // Commit transacción principal\n} catch (\\Exception $e) {\n    rollback(); // Rollback todo\n}\n\n// Verificar estado\nif (inTransaction()) {\n    $level = getTransactionLevel(); // Nivel de anidamiento\n}\n```\n\n### Múltiples Conexiones\n\n```php\n// Query con conexión específica\n$analyticsData = query('analytics')\n    -\u003eselect('*')\n    -\u003efrom('events')\n    -\u003ewhere(['date = ?' =\u003e date('Y-m-d')])\n    -\u003efetch();\n\n// Entidad con conexión específica\nclass AnalyticsEvent extends TableEntity {\n    protected static string $connection = 'analytics';\n    protected static string $entity = 'events';\n    // ...\n}\n\n// Transacción en conexión específica\ntransaction(function() {\n    // Operaciones en analytics\n}, 'analytics');\n\n// Obtener conexión directamente\n$pdo = db('analytics')-\u003egetPdo();\n```\n\n## Helpers Globales\n\n```php\n// Conexión\n$connection = db(?string $connection = null);\n\n// Query Builders\n$query = query(?string $connection = null);\n$insert = insert(?string $connection = null);\n$update = update(?string $connection = null);\n$delete = delete(?string $connection = null);\n\n// Transacciones\nbeginTransaction(?string $connection = null);\ncommit(?string $savepoint = null, ?string $connection = null);\nrollback(?string $savepoint = null, ?string $connection = null);\ntransaction(callable $callback, ?string $connection = null);\ninTransaction(?string $connection = null): bool;\ngetTransactionLevel(?string $connection = null): int;\n\n// Schema Registry\nschemaAlias(string $alias, string $realSchema);\nschemaBulkAlias(array $aliases);\n```\n\n## Arquitectura\n\n### Componentes Principales\n\n**Connection Layer**\n- `ConnectionManager`: Singleton que gestiona múltiples conexiones\n- `PDOConnection`: Implementación basada en PDO\n- `TransactionManager`: Manejo de transacciones con savepoints\n- __Lazy loading__: conexiones se crean solo cuando se usan\n\n**Query Builder**\n- `QueryBuilder`: Interfaz fluida para SELECT con joins, subqueries, unions\n- `InsertQuery`, `UpdateQuery`, `DeleteQuery`: Builders especializados\n- `Clauses/`: Implementaciones individuales (WHERE, JOIN, ORDER BY, etc.)\n- Prepared statements automáticos para seguridad\n\n**Entity System**\n- `EntityManager`: Clase base con hydration y change tracking\n- `TableEntity`: Active Record para tablas con CRUD\n- `ViewEntity`: Entidades read-only para vistas\n- `StoredProcedureEntity`: Ejecución de stored procedures\n- State tracking: new vs persisted, dirty fields, valores originales\n\n**Schema Registry**\n- `SchemaRegistry`: Singleton para mapeo de aliases\n- Permite cambiar schemas sin modificar código de entidades\n\n## Integración con Phobos Framework\n\nCuando se usa con Phobos Framework:\n\n1. Registra `DatabaseServiceProvider` en tu módulo\n2. El provider lee `config('database')` para configuración\n3. Servicios registrados en el Container:\n    - `db` → ConnectionInterface por defecto\n    - `db.manager` → ConnectionManager\n    - `db.transaction` → TransactionManager\n4. Acceso vía inyección de dependencias o helpers\n\n```php\n// En un controller\nclass UserController {\n    public function __construct(\n        private ConnectionInterface $db,\n        private TransactionManager $transactions\n    ) {}\n    \n    public function index() {\n        $users = User::find(['active = ?' =\u003e true]);\n        return Response::json($users);\n    }\n}\n```\n\n## Notas Importantes\n\n- **PHP 8.3+ requerido** - Usa typed properties, union types, named arguments\n- **Propiedades reservadas** - No uses: `_isNew`, `_original`, `_dirty`, `_reserved`, `schema`, `entity`, `pk`\n- **Change tracking automático** - `__set()` marca campos como dirty automáticamente\n- **Prepared statements siempre** - Todas las queries usan parameter binding\n- **Lazy loading** - Conexiones se crean solo cuando se usan por primera vez\n- **Sin ORM completo** - Es Active Record, no un ORM completo como Doctrine\n- **Schema aliasing** - Útil para multi-tenant, multi-ambiente, o testing\n\n## Testing\n\nPara testing de desarrollo:\n\n```json\n{\n  \"repositories\": [\n    {\n      \"type\": \"path\",\n      \"url\": \"../phobos-database\"\n    }\n  ],\n  \"require\": {\n    \"mongoose-studio/phobos-database\": \"*\"\n  }\n}\n```\n\n## Licencia\n\nMIT License - ver el archivo [LICENSE](LICENSE.txt) para más detalles.\n\n## Autor\n\n**Marcel Rojas**  \n[marcelrojas16@gmail.com](mailto:marcelrojas16@gmail.com)  \n__Mongoose Studio__\n\n## Contribuciones\n\nLas contribuciones son bienvenidas. Por favor:\n\n1. Fork el proyecto\n2. Crea una rama para tu feature (`git checkout -b feature/amazing-feature`)\n3. Commit tus cambios (`git commit -m 'Add amazing feature'`)\n4. Push a la rama (`git push origin feature/amazing-feature`)\n5. Abre un Pull Request\n\n---\n\n**Phobos Framework** by Mongoose Studio\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmongoose-studio%2Fphobos-framework-database","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmongoose-studio%2Fphobos-framework-database","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmongoose-studio%2Fphobos-framework-database/lists"}