Repository navigation
Releases: osumionline/framework
Release list
9.12.1 - Soporte para CURRENT_TIMESTAMP en DATETIME
Osumi Framework 9.12.1
Esta versión añade soporte para CURRENT_TIMESTAMP como valor por defecto dinámico de campos DATETIME en el ORM.
CURRENT_TIMESTAMP
Ahora puede definirse un campo DATETIME así:
#[OField(
type: OField::DATETIME,
nullable: false,
default: OField::CURRENT_TIMESTAMP
)]
public ?string $joined_at = null;Al generar el esquema SQL, se conserva correctamente como:
`joined_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMPEn runtime, el ORM resuelve OField::CURRENT_TIMESTAMP al timestamp actual en formato Y-m-d H:i:s cuando aplica los valores por defecto de un nuevo modelo.
generateModelFromDB
generateModelFromDB reconoce ahora las dos representaciones habituales de MariaDB:
CURRENT_TIMESTAMP
CURRENT_TIMESTAMP()
Ambas se generan en el modelo como:
default: OField::CURRENT_TIMESTAMPEsto permite importar correctamente esquemas reales que utilicen DEFAULT CURRENT_TIMESTAMP en columnas DATETIME.
Validación estricta
OField::CURRENT_TIMESTAMP solo puede utilizarse con campos OField::DATETIME.
Además, se diferencia expresamente del string literal:
'CURRENT_TIMESTAMP'por lo que un valor textual con ese contenido no se interpreta como una expresión SQL.
Las demás expresiones SQL dinámicas no soportadas, como UUID(), continúan rechazándose explícitamente.
Migración
Esta versión no añade un nuevo paso automático de migración.
Los proyectos que ya utilizan 9.12.0 pueden actualizar directamente mediante Composer:
composer update osumionline/framework --with-dependenciesDespués de actualizar puede volver a ejecutarse:
php of generateModelFromDB9.12.0 - Soporte nativo de DATE, DATETIME y BIGINT en el ORM
Osumi Framework 9.12.0
Esta versión amplía el ORM de Osumi Framework con soporte nativo para columnas SQL DATE, DATETIME y BIGINT, además de reforzar el sistema de migraciones del framework.
DATE y DATETIME
Hasta Osumi Framework 9.11, OField::DATE representaba realmente una columna SQL DATETIME.
A partir de 9.12 ambos tipos quedan separados:
OField::DATE → SQL DATE → PHP ?string → Y-m-d
OField::DATETIME → SQL DATETIME → PHP ?string → Y-m-d H:i:s
Los valores temporales se validan ahora de forma estricta, rechazando fechas u horas imposibles.
Los atributos automáticos #[OCreatedAt], #[OUpdatedAt] y #[ODeletedAt] continúan representando timestamps completos y utilizan internamente DATETIME.
El método OModel::get() y el pipe date de las plantillas admiten ambos tipos temporales.
BIGINT
Se añade el nuevo tipo:
OField::BIGINTLas columnas BIGINT se representan mediante propiedades PHP ?int y requieren un entorno PHP de 64 bits.
BIGINT también puede utilizarse como clave primaria mediante #[OPK], incluido autoincremento.
No se soportan columnas BIGINT UNSIGNED ni el modificador ZEROFILL.
generateModelFromDB
generateModelFromDB reconoce ahora correctamente:
DATE → OField::DATE
DATETIME → OField::DATETIME
BIGINT → OField::BIGINT
Las columnas SQL TIMESTAMP continúan rechazándose al no poder representarse fielmente mediante la semántica DATETIME del ORM.
Migración automática desde versiones anteriores
La versión 9.12.0 incluye un nuevo paso de migración.
Como OField::DATE significaba DATETIME antes de 9.12, los modelos existentes se actualizan automáticamente:
OField::DATEpasa a:
OField::DATETIMELa migración actúa únicamente sobre referencias PHP reales dentro de src/Model/, conservando comentarios y cadenas de texto.
No se modifica el esquema de la base de datos: los campos existentes mantienen su semántica DATETIME.
Después de la migración, los nuevos usos de OField::DATE representan columnas SQL DATE reales.
Nuevo estado persistente de migraciones
El estado autoritativo del sistema de migraciones deja de almacenarse en:
ofw/tmp/state.json
y pasa a:
.ofw-migrations.json
en la raíz del proyecto.
Este archivo debe versionarse junto con el código de la aplicación.
Para mantener la compatibilidad con proyectos existentes, durante la primera actualización el runner puede seguir leyendo el antiguo ofw/tmp/state.json cuando .ofw-migrations.json todavía no existe.
Este cambio evita que una limpieza de ofw/tmp/ pueda provocar accidentalmente la repetición de una migración ya ejecutada.
Actualización
La actualización puede realizarse normalmente mediante Composer:
composer update osumionline/framework --with-dependenciesLa migración 9.12.0 se ejecutará automáticamente cuando corresponda.
Después de actualizar, revisa los modelos modificados y añade .ofw-migrations.json al repositorio de la aplicación.
9.11.0 - Soporte nativo de campos DECIMAL exactos en el ORM
Osumi Framework 9.11.0
Osumi Framework 9.11.0 incorpora soporte nativo para campos SQL DECIMAL(p,s) en el ORM, manteniendo los valores decimales exactos durante todo su ciclo de vida y evitando conversiones intermedias a punto flotante.
Novedades
Soporte nativo para DECIMAL
Se añade el nuevo tipo:
OField::DECIMALLos campos DECIMAL deben representarse siempre mediante propiedades PHP ?string:
#[OField(
type: OField::DECIMAL,
precision: 12,
scale: 2,
nullable: false
)]
public ?string $amount = null;Los valores se mantienen como cadenas exactas y nunca se convierten a float.
La configuración predeterminada es:
precision:10scale:2
Los límites soportados son:
- precisión:
1a65 - escala:
0a30 scalenunca puede ser mayor queprecision
Normalización decimal
El ORM acepta tanto . como , como separador decimal de entrada:
"12" → "12.00"
"12.5" → "12.50"
"12,5" → "12.50"
"-0,50" → "-0.50"
La representación interna utiliza siempre . y conserva una escala fija.
No se admiten:
- valores
floatoint; - notación exponencial;
- separadores de miles;
- valores que requieran redondeo automático.
Los valores que superen la precisión o escala configuradas producen un error.
Consultas tipadas según el esquema
Las condiciones utilizadas por where() y count() se validan y normalizan ahora utilizando la definición del campo en el modelo.
Por ejemplo:
Payment::where([
'amount' => '12,5'
]);utiliza internamente:
12.50
mientras que utilizar un float para un campo DECIMAL es rechazado:
Payment::where([
'amount' => 12.5
]);También se rechazan condiciones que hagan referencia a campos inexistentes en el modelo.
Soporte en los generadores
Los comandos de generación del framework soportan ahora campos DECIMAL:
generateModelgenerateModelFromgenerateModelFromDB
generateModelFromDB conserva la precisión, la escala y los valores predeterminados de columnas DECIMAL como cadenas exactas.
Esto permite realizar correctamente el recorrido:
MariaDB / MySQL
→ modelo Osumi Framework
→ SQL generado
sin convertir los valores decimales a punto flotante.
Restricciones
OField::DECIMAL está disponible exclusivamente para #[OField].
No puede utilizarse en campos #[OPK].
Los parámetros precision y scale tampoco pueden utilizarse con otros tipos de OField.
Compatibilidad con PHP 8.5
Se corrige además la inicialización del esquema ORM para comprobar ReflectionProperty::hasDefaultValue() antes de llamar a ReflectionProperty::getDefaultValue().
Esto evita el aviso deprecado de PHP 8.5 al procesar propiedades que no tienen un valor predeterminado explícito.
Compatibilidad
La actualización desde Osumi Framework 9.10.2 es compatible hacia atrás.
Los proyectos existentes que no utilicen OField::DECIMAL no necesitan modificar sus modelos.
No existe ningún paso automático de migración para esta versión.
9.10.2 - Corrección del binding tipado de parámetros PDO en el ORM.
Osumi Framework 9.10.2 es una versión de mantenimiento que corrige el binding de parámetros del ORM al ejecutar sentencias preparadas con PDO.
Corrección
- Los valores
boolse bindean ahora mediantePDO::PARAM_BOOL. - Los valores
intutilizanPDO::PARAM_INT. - Los valores
nullutilizanPDO::PARAM_NULL. - El resto de valores escalares soportados utilizan
PDO::PARAM_STR. - La corrección se aplica de forma consistente a consultas, conteos, inserciones, actualizaciones y eliminaciones realizadas por
OModel.
Esto evita, entre otros casos, que valores booleanos como false puedan llegar a MySQL/MariaDB como una cadena vacía y provocar errores en columnas TINYINT(1) cuando se utiliza modo estricto.
Migración
No es necesario realizar ningún cambio en las aplicaciones existentes y esta versión no añade ningún nuevo paso automático de migración.
.10.1 - Corrección para emisión de códigos HTTP establecidos manualmente
Osumi Framework 9.10.1
Patch release que corrige la emisión de códigos HTTP establecidos manualmente mediante OCore::setHttpStatus().
Desde la introducción del pipeline de Middlewares en 9.9, el emisor final toma el código HTTP desde el estado interno de OMiddleware. setHttpStatus() seguía actualizando únicamente el estado interno de OCore, por lo que determinados componentes podían generar el cuerpo de error correcto y terminar enviando HTTP 200.
En 9.10.1:
OCore::setHttpStatus()sincroniza el código conOMiddleware.- Se restaura el comportamiento histórico de la API pública.
- Los Middlewares posteriores pueden seguir sobrescribiendo explícitamente el status.
- Se añade cobertura de regresión end-to-end.
No requiere cambios en aplicaciones existentes ni pasos automáticos de migración.
9.10.0 - Soporte para respuestas HTTP por streaming
Osumi Framework 9.10.0
Osumi Framework 9.10.0 incorpora soporte nativo para respuestas HTTP por streaming, pensado para servir archivos grandes o contenido generado progresivamente sin cargar el cuerpo completo en memoria.
OStreamResponse
Se añade OStreamResponse, una nueva respuesta HTTP basada en un stream PHP legible.
Permite configurar:
- cabeceras HTTP;
- código de estado;
- tamaño de bloque de lectura;
- cierre automático del recurso.
Los streams administrados por el framework se cierran al finalizar, al descartarse la respuesta o al destruirse el objeto.
Componentes streaming
Los componentes pueden devolver directamente un OStreamResponse desde run():
public function run(): OStreamResponseTambién se admiten las variantes con ORequest y DTO:
public function run(ORequest $req): OStreamResponse
public function run(MyDTO $dto): OStreamResponseCuando run() declara explícitamente OStreamResponse, el componente puede omitir su archivo de plantilla.
Una respuesta streaming no puede anidarse dentro de otro componente ni convertirse a string.
Integración con Middlewares
Las respuestas streaming mantienen el pipeline de Middlewares.
El flujo es:
before
↓
Componente
↓
OStreamResponse
↓
afterRender
↓
afterResponse
↓
Cierre de conexiones de base de datos
↓
Cabeceras HTTP
↓
Emisión del stream por bloques
No se envía ningún byte del stream hasta que afterRender y afterResponse han terminado.
Durante estas fases:
$data['is_streaming_response'] === trueLos Middlewares pueden modificar contexto, cabeceras y estado HTTP o detener la respuesta antes de comenzar la emisión.
No pueden sustituir body en una respuesta streaming, ya que no existe un cuerpo completo materializado en memoria.
Layouts
Los layouts se omiten automáticamente para respuestas OStreamResponse.
Las respuestas tradicionales basadas en plantillas mantienen exactamente el comportamiento anterior.
Gestión de recursos
La emisión se realiza por bloques, con un tamaño predeterminado de 1 MiB, evitando cargar archivos completos en memoria.
Antes de comenzar una descarga potencialmente larga, el framework libera las conexiones de base de datos que ya no son necesarias.
Si un Middleware detiene la petición antes de la emisión:
- el stream se descarta;
- no se envía ningún byte;
- se restauran las cabeceras normales;
- se genera la respuesta de error habitual.
También se han añadido validaciones para streams no legibles, cabeceras HTTP inválidas, códigos de estado y tamaños de bloque incorrectos.
Compatibilidad
9.10.0 es compatible hacia atrás con 9.9.1.
No requiere cambios en aplicaciones existentes y no añade ningún paso automático de migración.
Las respuestas tradicionales, componentes con plantilla, layouts y Middlewares existentes continúan funcionando sin cambios.
Documentación
La documentación se ha actualizado en:
- castellano;
- inglés;
- euskera;
- documentación específica para LLM;
llms.txt;- guía de migración 9.9.1 → 9.10.0.
9.9.1 - Corrección en la detección de rutas con Middlewares durante las migraciones
Osumi Framework 9.9.1 es una versión de mantenimiento que corrige un problema en el sistema de migraciones automáticas introducido en 9.9.0.
Corrección
- Se mejora la detección de rutas que ya utilizan Middlewares mediante
OMiddleware::PHASE_BEFORE,OMiddleware::PHASE_AFTER_RENDERyOMiddleware::PHASE_AFTER_RESPONSE. - Estas rutas ya no se interpretan incorrectamente como definiciones legacy de Filters durante la migración.
- Se añade cobertura de tests para este caso.
Migración
No hay cambios de API ni acciones necesarias por parte del usuario.
La versión 9.9.1 no añade un nuevo paso de migración; el último paso sigue siendo 9.9.0.
9.9.0 - Nuevo sistema de Middlewares y migraciones automáticas de proyectos.
Osumi Framework 9.9.0
Osumi Framework 9.9.0 incorpora un nuevo sistema nativo de Middlewares, sustituye la arquitectura anterior de Filters e introduce un motor de migraciones automáticas de proyectos integrado con Composer.
Se trata de una versión importante con cambios incompatibles para aplicaciones que utilicen Filters, pero incluye una migración automática diseñada para conservar su lógica actual mediante adaptadores de compatibilidad.
Middlewares
El nuevo pipeline permite ejecutar Middlewares en tres fases:
before: antes de ejecutar el componente.afterRender: después de renderizar el componente y antes del layout.afterResponse: después de generar la respuesta final y antes de enviarla.
Los Middlewares pueden configurarse a nivel:
- global
- grupo
- ruta
En cada fase se ejecutan en este orden:
global
→ grupo exterior
→ grupo interior
→ ruta
Un Middleware puede:
- publicar contexto;
- modificar el cuerpo de la respuesta;
- añadir o sustituir cabeceras;
- cambiar el código de estado HTTP;
- detener el pipeline mediante
stop; - devolver errores tipados según el tipo de respuesta.
Los Middlewares globales se configuran en:
src/Middleware/Middlewares.php
Contexto de Middleware
ORequest incorpora:
$req->getMiddleware('Login');
$req->getMiddlewareValue('Login', 'id');Los DTO también pueden utilizar contexto de Middleware como origen explícito:
#[ODTOField(
required: true,
middleware: 'Login',
middlewareProperty: 'id'
)]
public ?int $idUser = null;Esto permite utilizar valores de confianza generados en servidor, como el ID del usuario autenticado, sin aceptar sustituciones desde los parámetros enviados por el cliente.
Filters
Los Filters dejan de formar parte del runtime de Osumi Framework.
El código nuevo debe utilizar Middlewares.
También se elimina la creación de nuevos Filters mediante la CLI:
php of add --option middleware --name Logines ahora la forma recomendada de generar este tipo de lógica transversal.
Migraciones automáticas
9.9.0 incorpora un sistema de migraciones versionadas para actualizar proyectos cuando cambia la API del framework.
El paquete expone:
php vendor/bin/ofw-migratecon soporte para:
--from--to--dry-run--force--verbose--no-interaction--help
El estado se almacena en:
ofw/tmp/state.json
Las migraciones son idempotentes y los cambios se aplican de forma transaccional, con copias de seguridad y rollback automático en caso de error.
Integración con Composer
El nuevo sistema se integra con:
osumionline/plugin-updater
Durante una actualización mediante Composer, el plugin detecta la versión instalada y ejecuta automáticamente las migraciones pendientes después de regenerar el autoloader.
La aplicación debe autorizar el plugin en su composer.json:
{
"config": {
"allow-plugins": {
"osumionline/plugin-updater": true
}
}
}También están disponibles:
OFW_DRY_RUN
OFW_FORCE
OFW_VERBOSE
Migración automática de Filters
El paso de migración 9.9.0:
- detecta Filters antiguos bajo
src/Filter/; - conserva sus archivos y su lógica original;
- genera adaptadores
*Middleware.php; - transforma rutas con Filters a Middlewares
before; - cambia
getFilter()porgetMiddleware(); - cambia
filter/filterPropertyde DTO pormiddleware/middlewareProperty; - crea
src/Middleware/Middlewares.phpsi no existe.
La migración realiza primero un preflight completo y se detiene ante construcciones ambiguas que no pueda transformar de forma segura.
Entre los casos que requieren intervención manual están:
getFilters()
setFilter()
setFilters()
y las expresiones dinámicas de Filters utilizadas en rutas.
Semántica de stop
stop tiene la misma semántica en las tres fases.
- En
before, evita ejecutar el componente y el layout. - En
afterRender, evita aplicar el layout. - En ambos casos,
afterResponsesigue ejecutándose. - En
afterResponse, detiene los Middlewares restantes de esa fase y sustituye la respuesta final por el error tipado.
Los Middlewares afterResponse pueden inspeccionar el estado de errores producidos en fases anteriores.
Robustez y compatibilidad con PHP 8.5
Durante el desarrollo de 9.9 se ha realizado una auditoría amplia del framework, incluyendo mejoras en:
- tipado y contratos internos;
- routing y normalización;
- DTOs y
ORequest; - sesiones y ejecución CLI;
- ORM;
- configuración;
- manejo de errores;
- filesystem y operaciones temporales;
- validaciones de firmas de componentes;
- compatibilidad con PHP 8.5;
- eliminación de avisos deprecados.
También se corrigió OColors para evitar el uso de null como índice de array en PHP 8.5.
Nuevo skeleton
El repositorio osumionline/new ha sido actualizado para crear directamente proyectos 9.9 nativos:
- utiliza
src/Middleware/; - incluye
Middlewares.php; - los ejemplos usan Middlewares nativos;
- ya no incluye Filters;
- requiere
osumionline/framework ^9.9.0.
Documentación
La documentación se ha actualizado en:
- inglés;
- castellano;
- euskera.
Incluye:
- concepto completo de Middlewares;
- routing, DTOs, components, layouts, services y CLI;
- quickstart y recipes;
- documentación específica para LLM;
llms.txt;- guía completa de migración 9.8.5 → 9.9.0.
Compatibilidad
9.9.0 es incompatible a nivel de API con el antiguo runtime de Filters.
La migración automática proporciona un puente para proyectos existentes, pero los adaptadores generados están pensados como compatibilidad temporal.
Para nuevo desarrollo se deben utilizar siempre Middlewares nativos.
9.8.5 - Cambios en firma de métodos run de componentes. Nuevo pipe plain.
Osumi Framework 9.8.5
Esta versión incorpora mejoras en la ejecución de componentes y amplía las posibilidades de las plantillas con un nuevo pipe.
Novedades
-
Nuevas firmas para
run()en componentes- Los componentes ahora pueden definir
run()sin parámetros. - Se admiten explícitamente estas tres formas:
run(): voidrun(ORequest $req): voidrun(MyDTO $dto): void, dondeMyDTOextiendeODTO.
- Las firmas no compatibles se detectan y rechazan automáticamente.
- Los componentes ahora pueden definir
-
DTO independientes del namespace
- La detección de DTO ya no depende de que estén ubicados en un namespace concreto.
- Cualquier clase que extienda
ODTOpuede utilizarse directamente como parámetro derun(), independientemente de dónde esté ubicada dentro de la aplicación.
-
Nuevo pipe
plain- Se añade el pipe
plainpara utilizar cadenas de texto sin aplicarurlencode(). - La salida se genera de forma segura para JSON, escapando correctamente comillas y otros caracteres especiales.
- Los caracteres Unicode y las barras se conservan sin escapar.
- Los valores
nullse mantienen comonull.
- Se añade el pipe
Compatibilidad
Los componentes existentes que utilizan run(ORequest $req) o DTO que extienden ODTO continúan funcionando sin cambios.
El pipe string mantiene su comportamiento actual basado en urlencode(), por lo que plain se incorpora como una nueva alternativa sin modificar el comportamiento existente.
Documentación
La documentación del framework se ha actualizado en castellano, inglés y euskera para reflejar:
- Las nuevas firmas admitidas por
run(). - La detección de DTO mediante herencia de
ODTO. - El nuevo pipe
plain. - La nueva guía de migración de 9.8.4 a 9.8.5.
- La documentación específica para LLM y
llms.txt.
9.8.4 - Anidamiento con prefix y group y nuevo caso 401 para HttpStatus
Esta nueva versión trae una corrección y una mejora.
Corrección en getHttpStatus()
Se ha incorporado el caso 401 Unauthorized. Antes al intentar devolver este estado no lo reconocía y acababa devolviendo un HttpStatus 200.
Mejora en rutas
Se han mejorado los métodos estáticos ORoute::prefix y ORoute::group para permitir anidamiento. Ahora al hacer esto:
ORoute::prefix('/api', function(): void {
ORoute::get('/health', HealthComponent::class);
ORoute::prefix('/admin', function(): void {
ORoute::post('/login', LoginComponent::class);
ORoute::get('/me', MeComponent::class, [AdminAuthFilter::class]);
});
});Se generan las siguientes rutas correctamente:
/api/health/api/admin/login/api/admin/me
Además se ha añadido una normalización a todas las URLs creadas para evitar problemas con barras:
ORoute::prefix('/api/', function(): void {
ORoute::prefix('//admin///', function(): void {
ORoute::get('//users/', UsersComponent::class);
});
});Generará correctamente:
/api/admin/users
Esta normalización se ha añadido en todos los métodos estáticos de ORoute: get, post, put, delete, view, group y prefix