Actualizacion de Laravel Legacy

Actualizacion de Laravel Legacy: dónde empiezan los verdaderos problemas

«Vamos a actualizar Laravel» suena a una tarea sencilla. Hasta que abres composer.json. Un proyecto heredado (legacy) puede estar funcionando perfectamente en Laravel 7 u 8, pero la actualización a una versión moderna puede exponer toda una cadena de problemas de compatibilidad.

Estos son algunos de los más comunes al realizar una actualización de Laravel Legacy:

1. Un paquete utilizado por el proyecto antiguo no es compatible con el nuevo Laravel

Este es probablemente el escenario más frustrante. La aplicación utiliza un paquete que funcionaba perfectamente en Laravel 8:

Laravel 8
└── package-x 2.4

Actualizas a Laravel 11:

Laravel 11
└── package-x 2.4 ❌

Composer se niega a instalarlo porque el paquete requiere una versión más antigua de illuminate/*.

  • Ahora tienes que elegir:
  • buscar una versión más reciente;
  • reemplazar el paquete;
  • hacer un fork y mantenerlo tú mismo;
  • o posponer la actualización de Laravel.

Y, a veces, el paquete está abandonado, por lo que no hay ninguna ruta de actualización posible.

2. Conflictos de dependencias de Composer en la actualización de Laravel Legacy

Una sola actualización puede exponer conflictos a varios niveles de profundidad.

Por ejemplo:

Laravel 11
   ↓
requires Symfony 7
   ↓
Package A requires Symfony 6
   ↓
Package B requires Package A

Composer no puede satisfacer todos estos requisitos. La parte frustrante es que el paquete que causa el problema puede no ser algo que uses directamente. Puede ser una dependencia de otra dependencia. Ahí es donde una simple actualización del framework se convierte en arqueología de dependencias.

3. composer.lock puede mantener el árbol de dependencias antiguo

Actualizas composer.json:

"laravel/framework": "^11.0"

Pero Composer sigue reportando conflictos porque composer.lock contiene versiones de la aplicación antigua. El archivo lock representa el árbol de dependencias que fue resuelto previamente.

Por lo tanto, a veces necesitas actualizar no solo Laravel, sino un grupo cuidadosamente seleccionado de dependencias relacionadas, sin borrar a ciegas el composer.lock y esperar lo mejor.

4. La nueva versión de Laravel requiere un PHP más reciente

Por ejemplo:
Aplicación antigua

Laravel 8
PHP 7.4

pasa a ser:

Laravel 11
PHP >= 8.2

Pero actualizar PHP puede exponer otra capa de problemas. Es posible que algunos paquetes antiguos ya no sean compatibles con PHP 8.2. Así que la cadena de dependencias se convierte en:

Laravel upgrade
      ↓
PHP upgrade
      ↓
old packages become incompatible
      ↓
packages need upgrading/replacing
      ↓
application code needs changes

5. El paquete tiene una nueva versión, pero su API ha cambiado

Este es fácil de subestimar. Encuentras una versión compatible y Composer la instala con éxito. Genial.

Excepto que el código antiguo:

SomePackage::process($data);

ahora podría requerir:

SomePackage::process($data, $options);

o el método puede haber sido renombrado, eliminado o haber cambiado su tipo de retorno. Por lo tanto: éxito de Composer ≠ éxito de la aplicación.

6. Las actualizaciones de Symfony pueden afectar a las aplicaciones Laravel

Laravel depende en gran medida de los componentes de Symfony. Cuando Laravel pasa a versiones más recientes de Symfony, el código personalizado o los paquetes creados en torno al comportamiento antiguo de Symfony pueden dejar de funcionar. Esto es especialmente relevante para proyectos con integraciones personalizadas, manejo de HTTP, comandos de consola, correo, eventos o funcionalidad del sistema de archivos.

7. Las actualizaciones de Flysystem pueden romper las integraciones del sistema de archivos

Un buen ejemplo es el cambio a Flysystem 3. Una aplicación antigua puede tener:

Laravel
└── Flysystem 1/2
    └── custom storage adapter

Tras la actualización:

Laravel
└── Flysystem 3
    └── old adapter ❌

La aplicación Laravel en sí puede ser compatible, pero un adaptador personalizado o un paquete creado en torno a la antigua API de Flysystem podría no serlo.

8. Los paquetes de autenticación tienen sus propias rutas de actualización

Laravel Passport, Sanctum, Socialite y otros paquetes del ecosistema no avanzan necesariamente a la par que Laravel. Puedes terminar con:

Laravel → new version
Passport → old version
      ↓
incompatible dependencies

O puedes actualizar Passport y luego descubrir que los flujos de autenticación, la configuración o las migraciones de la base de datos necesitan cambios.

9. Las migraciones de los paquetes pueden cambiar

Este es otro problema sutil. Un paquete puede instalarse correctamente, pero su configuración de base de datos podría funcionar de manera diferente en una versión más reciente. Actualizas el paquete, despliegas la aplicación y de repente descubres que las tablas, columnas o índices esperados no están presentes. Por esta razón, las actualizaciones de paquetes deben tratarse como cambios en la aplicación, no solo como cambios en Composer.

10. PHPUnit y la suite de pruebas pueden convertirse en otra migración

El código de producción puede seguir pareciendo correcto. Luego ejecutas:

php artisan test

y la mitad de la suite de pruebas falla. ¿Por qué? Porque las versiones de PHPUnit compatibles con Laravel cambian con el tiempo, y el propio PHPUnit elimina las API obsoletas. Así que actualizar Laravel puede significar actualizar:

Laravel
+
PHP
+
Composer packages
+
PHPUnit
+
test code

11. La configuración y la estructura de la aplicación pueden cambiar

Una versión más reciente de Laravel puede introducir una estructura predeterminada o un enfoque de configuración diferentes. La tentación es tomar una instalación limpia de Laravel y copiar todo en el proyecto antiguo. A menudo, esto es una mala idea. Una aplicación heredada tiene años de configuración personalizada, middleware, proveedores de servicios e integraciones. El objetivo no es hacer que la aplicación antigua se vea como una instalación limpia de Laravel. El objetivo es trasladar la aplicación existente de forma segura a la nueva versión del framework.

Y esto es lo que hace que las actualizaciones de Laravel sean difíciles. El problema rara vez es:

«¿Cómo instalo Laravel 11?»

El verdadero problema es:

«¿Qué partes de este árbol de dependencias de hace 7 años pueden realmente pasar a Laravel 11 sin romper la aplicación?»

Antes de actualizar, me gustaría saber:

  • ¿Qué paquetes bloquean la actualización?
  • ¿Qué paquetes están abandonados?
  • ¿Qué paquetes necesitan ser reemplazados?
  • ¿Qué versión de PHP se requiere?
  • ¿Qué versiones de Symfony/Flysystem van a cambiar?
  • ¿Qué versiones mantiene fijas actualmente composer.lock?
  • ¿Qué APIs tienen cambios que rompen la compatibilidad (breaking changes)?
  • ¿Qué migraciones de base de datos se ven afectadas?
  • ¿Seguirá funcionando la suite de pruebas existente?
  • ¿Qué flujos críticos para el negocio necesitan pruebas de regresión?

Porque en una aplicación Laravel heredada (legacy), la ruta de actualización a menudo es más complicada que la actualización en sí.

¿Cuál ha sido el mayor obstáculo que has encontrado al actualizar Laravel: un paquete incompatible, conflictos de Composer, PHP, o alguna otra cosa?

Leer más:

– Modernización de sistemas heredados: Cómo actualizar sistemas críticos del sector público sin interrupciones