Documentación de Leviatan Framework
Guía detallada para usar el proyecto base de forma correcta: convenciones, comandos y buenas prácticas.
Introducción
Leviatan es un esqueleto de aplicación PHP con un núcleo reusable en framework/, código de producto en app/ y front controller en public/index.php. Integra AltoRouter para rutas, Doctrine DBAL + ORM 3 para datos, Smarty 5 para plantillas y una pila PSR-7 / PSR-15 (Nyholm PSR-7 + middlewares propios).
El objetivo es predecibilidad: pocos conceptos, nombres claros y documentación que puedas seguir sin adivinar comportamientos ocultos.
Requisitos
- PHP 8.3 o superior (en 8.4+ el ORM puede usar proxies nativos).
- Composer para dependencias.
- Extensiones habituales: json, mbstring, y el driver PDO de tu base (p. ej. pdo_sqlite o pdo_mysql).
Instalación
composer install
cp .env.example .env
Opcional: ajusta DATABASE_URL en .env. Si la omites, el proyecto usa SQLite en var/app.db (crea el directorio var/ con permisos de escritura).
Aplica migraciones cuando toque una base nueva:
composer migrate
Servidor de desarrollo:
composer serve
URLs útiles: / (landing), /documentacion (este manual), /consola (panel técnico de ejemplo), /showcase, /health (JSON).
Estructura del proyecto
- framework/ — Núcleo reusable (HTTP, routing, ORM factory, middlewares, vistas).
- app/ — Controladores, entidades, repositorios, vistas y config/routes.web.php.
- config/bootstrap.php — Arranque: entorno, BD, EntityManager, contenedor, vista, kernel.
- public/ — Único directorio expuesto al servidor web (index.php, .well-known).
- database/migrations/ — Clases de migración Doctrine.
- var/ — SQLite, logs, proxies ORM (no versionar datos sensibles).
Bootstrap
Cada front controller hace require de config/bootstrap.php, que devuelve una instancia de Leviatan\Framework\Bootstrap\Application ya configurada con servicios (db, em, view, logger, kernel, etc.).
Variables de entorno relevantes
- APP_ENV, APP_DEBUG — En producción mantén APP_DEBUG=false.
- DATABASE_URL — DSN Doctrine DBAL.
- SESSION_SECURE, SESSION_SAMESITE — Cookies de sesión (HTTPS en prod).
Enrutado
Las rutas HTTP se registran en app/config/routes.web.php con el router inyectado:
$router->map('GET', '/ruta', [MiController::class, 'metodo'], 'nombre_opcional');
El primer patrón que coincida gana. Para APIs REST suele bastar con métodos y paths explícitos; consulta la documentación de AltoRouter si necesitas parámetros nombrados en el path.
Controladores
Los controladores son clases en app/Controllers/. El método de acción recibe Psr\Http\Message\ServerRequestInterface $request y array $params (parámetros de ruta).
Pueden devolver una cadena HTML (vista) o un objeto Psr\Http\Message\ResponseInterface (por ejemplo JSON; usa HttpResponseFactory si conviene).
El contenedor League Container con ReflectionContainer permite inyectar dependencias en el constructor (ViewRendererInterface, EntityManager, HealthService, etc.) sin registrar cada clase manualmente.
Inyección de dependencias
En config/bootstrap.php se registran servicios compartidos: Connection, EntityManager, Application, LoggerInterface, etc. Los controladores se resuelven con $container->get(Clase::class) cuando el contenedor puede construirlos.
Vistas Smarty
Las plantillas viven en app/Views/. La clase correcta es Smarty\Smarty (Smarty 5). Cualquier bloque CSS con llaves { } debe ir dentro de ... para no chocar con la sintaxis Smarty.
Asigna variables desde el controlador con el array pasado a render(); en la plantilla usa salvo que confíes al 100% en el origen del dato.
Base de datos (DBAL)
Obtén la conexión con $app->get('db') o inyectando Doctrine\DBAL\Connection. Usa siempre consultas parametrizadas; no concatenes entrada de usuario en SQL crudo.
ORM y entidades
Las entidades están en app/Entity/ con atributos PHP de Doctrine ORM 3. El EntityManager está disponible como $app->get('em') o por inyección. Los repositorios personalizados van en app/Repository/ y se referencian en #[Entity(repositoryClass: ...)].
Herramienta web de modelos
La ruta /herramienta/modelos (requiere contexto WEB y proyecto ya instalado) abre un asistente con formularios para definir entidades (estilo Doctrine del proyecto), repositorios y, si lo indicas, una migración y su aplicación. Opcionalmente puedes pegar un JSON declarativo; las FK referencian otras clases del mismo envío. En el primer acceso debes crear usuario y contraseña (se guardan en var/model_tool_auth.json; no versionar). Vuelve a entrar cuando quieras; el acceso está protegido por sesión tras autenticarte.
Migraciones
Configuración en config/cli-config.php. Comando habitual: composer migrate. Tras cambiar el esquema, genera y revisa migraciones antes de desplegar en entornos compartidos.
HTTP y middlewares
El HttpKernel envuelve la aplicación con middlewares en orden: identificación de petición, manejo de errores (con logs), cabeceras de seguridad, sesión y CSRF en métodos que alteran estado.
Application::handleRequest() trabaja con ServerRequestInterface y devuelve ResponseInterface; el último middleware interno es ApplicationRequestHandler.
Sesión y CSRF
Formularios que muten datos (POST, PUT, PATCH, DELETE) deben incluir el token CSRF que expone la aplicación tras abrir sesión (campo _csrf o cabecera equivalente). Configura SESSION_SECURE=true cuando sirvas solo por HTTPS.
Logging
Usa Psr\Log\LoggerInterface desde el contenedor. En depuración los logs van a stderr; en producción, a var/log/app.log con rotación (o a stderr si no hay permisos de escritura). Las respuestas 500 registran contexto con request_id cuando la petición pasó por el middleware de ID.
Salud y monitorización
GET /health devuelve JSON con status y comprobaciones (p. ej. base de datos). Usa códigos HTTP adecuados (503 si degradado). La cabecera X-Request-ID ayuda a correlacionar logs en soporte.
Tests y calidad
- composer test — PHPUnit.
- composer test:smoke — Comprobación rápida del bootstrap y rutas clave.
- composer analyse — PHPStan (nivel 6 + extensiones PHPUnit y Doctrine).
- composer check — Valida composer, PHPStan, tests y smoke.
Despliegue
El document root del servidor debe ser solo public/. No expongas vendor/, .env ni var/ por HTTP. Lee docs/production.md y sustituye public/.well-known/security.txt con datos reales de contacto.
Preguntas frecuentes
¿Necesito Docker?
No. Docker es opcional para desarrollo; en servidor puedes usar Apache o Nginx + PHP-FPM como cualquier app PHP.
¿Dónde pongo la lógica de negocio?
En app/ (servicios, modelos de dominio). Mantén framework/ libre de reglas de negocio del producto.
¿Puedo quitar Smarty?
Sí: el bootstrap cae en PhpViewRenderer si Smarty no está disponible; las plantillas .tpl tendrían que migrarse a PHP puro o a otro motor.
¿Algo no cuadra? Revisa AGENTS.md en el repositorio para convenciones orientadas a IA y equipos.