Si hay algo que me apasiona en el desarrollo web, es encontrar herramientas que simplifiquen la vida sin comprometer el rendimiento. ORMs como Doctrine son potentes, pero a menudo vienen con configuraciones complejas y una curva de aprendizaje empinada. Hace poco me encontré Composite DB, un ORM minimalista que puedes tener funcionando en menos de 5 minutos. ¿Te gustaría conocer una opción ligera y rápida para tus proyectos en PHP 8.1+? ¡Sigue leyendo!
¿Qué es Composite DB?
Composite DB es un ORM ultraligero diseñado para PHP 8.1+. Su filosofía es clara: menos configuración, más acción. Aprovecha las características modernas de PHP para ofrecerte un código limpio y un rendimiento ágil, ideal para proyectos donde la velocidad y la simplicidad son prioridad.
Lo mejor de PHP 8.1+ en tus manos
Composite DB saca el máximo provecho de las novedades de PHP. Mira este ejemplo de una entidad:
<?php
// src/Entity/User.php
namespace App\Entity;
use Composite\DB\Attributes\{Table, PrimaryKey};
use Composite\Entity\AbstractEntity;
use App\Enums\Status;
#[Table(connection: 'sqlite', name: 'Users')]
class User extends AbstractEntity
{
#[PrimaryKey(autoIncrement: true)]
public readonly int $id;
public function __construct(
public string $email,
public ?string $name = null,
public bool $is_test = false,
public Status $status = Status::ACTIVE,
public readonly \DateTimeImmutable $created_at = new \DateTimeImmutable(),
) {}
}
- Enums nativos: Usa Status para definir estados como
ACTIVE
oBLOCKED
de forma clara. - Propiedades inmutables:
id
ycreated_at
sonreadonly
, garantizando datos consistentes. - Atributos PHP: Con
#[Table]
y#[PrimaryKey]
, mapeas la entidad a la base de datos sin complicaciones.
¿Cuándo brilla Composite DB?
Este ORM es perfecto para escenarios donde necesitas moverte rápido:
- APIs RESTful: Crea endpoints para apps móviles en minutos.
- Prototipos rápidos: Valida ideas sin perder tiempo en configuraciones.
- Proyectos IoT: Gestiona datos de sensores con pocos recursos.
Tutorial práctico: API con Composite DB y Slim Framework
Vamos a construir una API sencilla usando Composite DB y Slim con SQLite como base de datos. ¡Sigue estos pasos y tendrás algo funcional en poco tiempo!
1.- Instalar dependencias
Crea un nuevo proyecto e instala las dependencias con Composer:
mkdir CompositeDB-Slim
cd CompositeDB-Slim
composer init --name="tu-nombre/composite-db-slim" --require="php:^8.1"
composer require slim/slim:^4.0 slim/psr7 composite/db vlucas/phpdotenv
2.- Configurar la conexión a la base de datos
Composite DB necesita un archivo de configuración para la conexión. Crea src/Config/ConnectionManager.php
:
[
'driver' => 'pdo_sqlite',
'path' => DB_PATH, //SQLite creará este archivo si no existe
],
];
Luego, configura la variable de entorno CONNECTIONS_CONFIG_FILE
usando phpdotenv
. Crea un archivo .env
en la raíz del proyecto:
CONNECTIONS_CONFIG_FILE=../src/Config/ConnectionManager.php
Tip: La ruta ../src/Config/ConnectionManager.php
es relativa al directorio public/
, desde donde se ejecuta index.php
. Esto asegura que Composite DB encuentre el archivo correctamente.
3.- Definir el modelo y la tabla
Crea el enum Status
en src/Enums/Status.php
:
<?php
namespace App\Enums;
enum Status: string
{
case ACTIVE = 'ACTIVE';
case BLOCKED = 'BLOCKED';
}
Usa la entidad User que mostramos antes (src/Model/User.php)
.
Ahora, define la clase de tabla en src/Model/UsersTable.php
:
<?php
namespace App\Table;
use Composite\DB\AbstractTable;
use App\Entity\User;
class UsersTable extends \Composite\DB\AbstractTable
{
protected function getConfig(): \Composite\DB\TableConfig
{
return \Composite\DB\TableConfig::fromEntitySchema(User::schema());
}
/**
* @return User[]
*/
public function findAllActive(): array
{
return $this->_findAll(['status' => \App\Enums\Status::ACTIVE]);
}
public function init(): void
{
$this->getConnection()->executeStatement("
CREATE TABLE IF NOT EXISTS Users
(
`id` INTEGER
CONSTRAINT Users_pk PRIMARY KEY AUTOINCREMENT,
`email` VARCHAR(255) NOT NULL,
`name` VARCHAR(255) DEFAULT NULL,
`is_test` INT DEFAULT 0 NOT NULL,
`status` TEXT DEFAULT 'ACTIVE' NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CHECK (status IN ('ACTIVE', 'BLOCKED'))
);
");
}
}
Nota: Llama a init()
una vez para crear la tabla. Puedes hacerlo manualmente o en el código inicial (lo veremos más adelante).
4.- Configurar Slim y las rutas
Crea public/index.php
con la lógica de la API:
<?php
declare(strict_types=1);
use App\Controllers\RootController;
use App\Controllers\UserController;
use DI\ContainerBuilder;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Dotenv\Dotenv;
require __DIR__ . '/../vendor/autoload.php';
// Cargar variables de entorno
$dotenv = Dotenv::createImmutable(__DIR__ . '/../');
$dotenv->load();
// Configurar PHP-DI
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
\App\Table\UsersTable::class => \DI\create(\App\Table\UsersTable::class)
]);
// Construir el contenedor
$container = $containerBuilder->build();
// Configurar Slim con el contenedor
AppFactory::setContainer($container);
$app = AppFactory::create();
$app->addRoutingMiddleware();
// Inicializar la base de datos (descomentar solo la primera vez)
// $container->get(App\Table\UsersTable::class)->init();
// Rutas
$app->get('/', [RootController::class, 'index']);
$app->get('/users', [UserController::class, 'list']);
$app->post('/users', [UserController::class, 'create']);
$app->run();
5.- Probar la API
Crea el directorio database/
en la raíz del proyecto:
mkdir database
Nota: En el repositorio incluyo una base datos SQlite con ejemplos pero si deseas hacerlo desde cero, este es el inicio.
Inicia el servidor de desarrollo:
php -S localhost:8000 -t public
Prueba las rutas:
- Listar usuarios activos:
curl http://localhost:8000/
Respuesta esperada:
{
"data": [],
"message": "Usuarios activos obtenidos correctamente"
}
- Mostrar los usuarios activos:
curl -X GET http://localhost:8000/users
Respuesta esperada:
{
"status": "success",
"data": [
{
"id": 1,
"email": "[email protected]",
"name": "John",
"is_test": false,
"status": "ACTIVE",
"created_at": "2025-04-10 22:24:20.128227"
},
{
"id": 2,
"email": "[email protected]",
"name": "Martie",
"is_test": false,
"status": "ACTIVE",
"created_at": "2025-04-10 22:56:49.105486"
}
],
"message": "Usuarios activos obtenidos correctamente"
}
- Crear un usuario:
curl -X POST http://localhost:8000/users -H "Content-Type: application/json" -d '{"email":"[email protected]","name":"Test User"}'
Respuesta esperada:
{
"data": {
"id": 1,
"email": "[email protected]",
"name": "Test User",
"is_test": false,
"status": "ACTIVE",
"created_at": "2025-04-10T20:00:00+00:00"
},
"message": "Usuario creado correctamente"
}
Limitaciones y cómo sacarle partido
Composite DB no está diseñado para relaciones complejas (como joins automáticos), pero eso no es un obstáculo si sabes adaptarte:
- Consultas SQL manuales: Usa
$usersTable->getConnection()->executeQuery()
para consultas personalizadas. - Caché opcional: Aunque no lo usamos aquí, Composite DB soporta caché ligero para acelerar consultas recurrentes.
- Simplicidad como fortaleza: Su enfoque minimalista reduce el overhead y mantiene el código claro.
Por ejemplo, para un join manual:
/**
* @return User[]
*/
public function findAllActiveAdults(): array
{
return $this->_findAll(
new Where(
'age > :age AND status = :status',
['age' => 18, 'status' => Status::ACTIVE->name],
)
);
}
Lecciones aprendidas de la documentación
La documentación de Composite DB puede ser confusa:
- Rutas relativas: No siempre queda claro cómo configurar
CONNECTIONS_CONFIG_FILE
. Usarphpdotenv
y una ruta relativa desdepublic/
(como../src/Config/ConnectionManager.php
) resuelve el problema. - Configuración inicial: Tuve que experimentar para entender cómo el ORM carga el archivo de conexión. Mi consejo: verifica que las rutas sean correctas según tu estructura de carpetas.
Recomendamos usar phpdotenv
para una configuración más limpia y asegurarte de que la ruta al archivo de configuración sea correcta según tu estructura de proyecto.
¿Quién está usando Composite DB?
Este ORM está ganando adeptos en:
- Startups: Ideal para lanzar productos rápidamente.
- DevOps: Fácil de integrar con herramientas como Prometheus o Grafana.
¿Es Composite DB para ti?
Si valoras:
- Simplicidad extrema: Configuración mínima, resultados inmediatos.
- Rendimiento ágil: Como si fuera serverless.
- PHP moderno: Aprovecha enums, propiedades readonly y atributos.
…¡Entonces es tu herramienta! Si necesitas migraciones complejas o transacciones avanzadas, considera opciones como Doctrine.
Composite DB es una joya para proyectos pequeños, experimentos o cualquier situación donde quieras velocidad y simplicidad. Te dejo el código de ejemplo en este repositorio para que lo explores. ¿Te animas a probarlo en tu próximo proyecto?
Deja una respuesta