Cómo actualizar las aplicaciones de Symfony 2.0 a Symfony 2.1
Actualizar a Symfony 2.1 una aplicación desarollada con Symfony 2.0 es un proceso necesariamente manual y que requiere de varios pasos que debes realizar en el orden adecuado.
El único recurso oficial que existe sobre la actualización es el famoso documento UPGRADE que explica detalladamente todos los cambios que tienes que hacer en el código de una aplicación Symfony 2.0 para que funcione en Symfony 2.1.
El problema es que actualizar la aplicación tal y como explica ese documento no es
suficiente, ya que por ejemplo no menciona cómo pasar del viejo archivo deps
al
archivo composer.json
que utiliza Symfony 2.1 para gestionar los vendors.
Recientemente hemos actualizado a Symfony 2.1 la aplicación Cupon que se programó para Symfony 2.0. Este artículo es el resumen de todo lo aprendido sobre cómo actualizar una aplicación Symfony 2.0 a 2.1. Aunque este artículo sea un poco largo, no te asustes porque el proceso de actualización no es tan complicado.
Primeros pasos
Si utilizas Git para controlar el código de tu aplicación, asegúrate de estar en la rama de la versión 2.0 y crea a partir de ella la nueva rama para Symfony 2.1. En nuestro caso, esto fue tan sencillo como ejecutar el siguiente comando:
$ git checkout -b 2.1
Convertir el archivo deps
en composer.json
Symfony incluye decenas de librerías y herramientas creadas por terceros. Para
gestionar esas dependencias, Symfony 2.0 utiliza un sistema propio basado en
un archivo de configuración llamado deps
. Por su parte, Symfony 2.1 emplea
una solución mucho más sencilla, completa y profesional basada en la herramienta
Composer
.
Lamentablemente no existe una utilidad para crear automáticamente el archivo
de configuración composer.json
a partir del archivo deps
. Así que crea un
nuevo archivo llamado composer.json
en la raíz de tu proyecto con el siguiente
contenido:
{ "name": "javiereguiluz/cupon", "description": "Aplicación de prueba para aprender a programar con Symfony 2.1", "autoload": { "psr-0": { "": "src/" } }, "require": { "symfony/framework-standard-edition": "2.1.*" }, "scripts": { "post-install-cmd": [ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile" ], "post-update-cmd": [ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile" ] }, "minimum-stability": "dev" }
Cambia el valor de las opciones name
y description
por algo más adecuado para
tu proyecto. Las demás partes no las modifiques, por muy raras que te parezcan. La
opción scripts
es la que hace que después de cada actualización de Symfony2 se
regenere el archivo bootstrap.php
, se borre la caché y se generen todos los assets
(archivos CSS y JavaScript).
La opción require
es la más importante, ya que indica qué paquetes deben
instalarse en tu aplicación:
"require": { "symfony/framework-standard-edition": "2.1.*" },
La configuración anterior hace que Symfony siempre se actualice a la versión más reciente que exista en la rama 2.1. Si eres un programador precavido, quizás prefieras indicar una versión exacta de Symfony 2.1:
"require": { "symfony/framework-standard-edition": "2.1.1" },
De esta manera, cuando salga una nueva versión de Symfony 2.1 podrás probarla tranquilamente en tu entorno de desarrollo sabiendo que todavía no se ha actualizado en la aplicación de producción
Declarar las dependencias propias
Tu aplicación seguramente utiliza varios bundles de Symfony2 desarrollados por
terceros y otras librerías y herramientas no incluidas en Symfony2. En la aplicación
Cupon
por ejemplo se utilizan los fixtures de Doctrine (a través de
DoctrineFixturesBundle
) y un paginador (a través de IdeupSimplePaginatorBundle
).
Por eso el archivo deps
incluye estas dependencias propias:
[doctrine-fixtures] git=http://github.com/doctrine/data-fixtures.git [DoctrineFixturesBundle] git=http://github.com/doctrine/DoctrineFixturesBundle.git target=/bundles/Symfony/Bundle/DoctrineFixturesBundle version=origin/2.0 [doctrine-extensions] git=https://github.com/beberlei/DoctrineExtensions.git [IdeupSimplePaginatorBundle] git=https://github.com/javiacei/IdeupSimplePaginatorBundle target=/bundles/Ideup/SimplePaginatorBundle
Lo que debes hacer es transformar esas dependencias en requerimientos de Composer
.
El truco para hacerlo está en que el archivo deps
es tan torpe que hay que indicar
una por una todas las dependencias de cada bundle. Sin embargo, Composer
es
tan avanzado que sólo tienes que decirle el bundle que quieres instalar y el
se encarga de instalar también todas las librerías y dependencias que necesite.
Así que la configuración anterior se transforma en lo siguiente:
"require": { "symfony/framework-standard-edition": "2.1.*", "doctrine/doctrine-fixtures-bundle": "dev-master", "ideup/simple-paginator-bundle": "dev-master" },
Para encontrar el nombre completo de la dependencia que corresponde a cada bundle,
puedes acceder a la sección de bundles de este sitio y buscar el
bundle que utilizas. Después, sólo tienes que consultar las instrucciones de
instalación en Symfony 2.1 o directamente el valor de la opción name
de su
archivo composer.json
.
Después de este proceso, el archivo composer.json
completo resultante es el siguiente:
{ "name": "javiereguiluz/cupon", "description": "Aplicación de prueba para aprender a programar con Symfony 2.1", "autoload": { "psr-0": { "": "src/" } }, "require": { "symfony/framework-standard-edition": "2.1.*", "doctrine/doctrine-fixtures-bundle": "dev-master", "ideup/simple-paginator-bundle": "dev-master" }, "scripts": { "post-install-cmd": [ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile" ], "post-update-cmd": [ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile" ] }, "minimum-stability": "dev" }
Instalación de los nuevos vendors
El siguiente paso consiste en borrar el actual directorio vendor/
de tu proyecto.
Borra el directorio entero, no sólo sus contenidos. Y no te preocupes por perder cosas,
ya que en el directorio vendor/
no deberías haber hecho ningún cambio local ni
deberías haber añadido ningún código.
Después, instala los nuevos vendors ejecutando el siguiente comando desde el directorio raíz de tu proyecto:
En Windows:
> php composer.phar install
En Linux y Mac OS X:
$ composer install
Para que los comandos anteriores te funcionen bien, Composer
debe estar instalado
globalmente en tu ordenador. Consulta la
guía de instalación de Composer
para saber cómo hacerlo.
Actualizar los archivos de Symfony 2.1
En el directorio app/
de tu aplicación existen varios archivos importantes de
Symfony2. Seguramente el más importante es app/autoload.php
, que hace que las
clases PHP se carguen de forma automática.
En Symfony 2.0 este archivo tenía decenas de líneas. En Symfony 2.1 simplemente tiene los siguientes contenidos:
use Doctrine\Common\Annotations\AnnotationRegistry; $loader = require __DIR__.'/../vendor/autoload.php'; // intl if (!function_exists('intl_get_error_code')) { require_once __DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs/functions.php'; $loader->add('', __DIR__.'/../vendor/symfony/symfony/src/Symfony/Component/Locale/Resources/stubs'); } AnnotationRegistry::registerLoader(array($loader, 'loadClass')); return $loader;
A continuación, te indicamos la lista de archivos que debes actualizar y un enlace a los nuevos contenidos de cada uno:
- Reemplaza el contenido de
app/autoload.php
por lo siguiente raw.github.com/.../app/autoload.php - Reemplaza el contenido de
app/check.php
por lo siguiente raw.github.com/.../app/check.php - Reemplaza el contenido de
app/console
por lo siguiente raw.github.com/.../app/console - Reemplaza el contenido de
web/app.php
por lo siguiente raw.github.com/.../web/app.php - Reemplaza el contenido de
web/app_dev.php
por lo siguiente raw.github.com/.../web/app_dev.php - Reemplaza el contenido de
web/config.php
por lo siguiente raw.github.com/.../web/config.php
Obviamente, antes de machacar el contenido de tus archivos piensa si has hecho
algún cambio en ellos (sobre todo en app.php
y app_dev.php
). El archivo
app/autoload.php
seguramente contiene modificaciones tuyas, pero puedes borrarlas
con seguridad, ya que Composer
hace que no sea necesario registrar los
namespaces a mano.
Mención aparte merece el archivo app/AppKernel.php
. Symfony2 no realiza ningún
cambio en este archivo, pero puede ser necesario que tu realices algunas modificaciones.
Concretamente, algún bundle puede dejar de funcionar porque su namespace ha
cambiado para Symfony 2.1 y ya no se puede registrar de la misma manera que en
Symfony 2.0. El ejemplo más claro son los fixtures de Doctrine2:
Registrar el bundle de fixtures en Symfony 2.0:
class AppKernel extends Kernel { public function registerBundles() { $bundles = array( // ... new Symfony\Bundle\DoctrineFixturesBundle\DoctrineFixturesBundle(), ); // ... } }
Registrar el bundle de fixtures en Symfony 2.1:
class AppKernel extends Kernel { public function registerBundles() { $bundles = array( // ... new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(), ); // ... } }
Nuestro consejo es que no pierdas el tiempo comprobando si los bundles han cambiado sus namespaces. Ejecuta la aplicación y si ves algún mensaje de error que indica que no se ha podido encontrar o registrar algún bundle, actualiza su namespace. Para encontrar el namespace correcto en Symfony 2.1, puedes consultar de nuevo la sección de los bundles de este sitio.
Actualizar las opciones de configuración
El cambio más importante relacionado con la configuración es que en Symfony 2.1
el locale
ya no depende de la sesión sino de la petición. Además, la opción
auto_start
de las sesiones ya no existe porque se gestiona automáticamente:
Configuración original de 2.0:
# app/config/config.yml framework: esi: { enabled: true } translator: { fallback: es } secret: %secret% router: { resource: "%kernel.root_dir%/config/routing.yml" } form: true csrf_protection: true validation: { enable_annotations: true } templating: { engines: ['twig'] } session: default_locale: %locale% auto_start: true
Nueva configuración de 2.1:
# app/config/config.yml framework: default_locale: %locale% esi: { enabled: true } translator: { fallback: es } secret: %secret% router: { resource: "%kernel.root_dir%/config/routing.yml" } form: true csrf_protection: true validation: { enable_annotations: true } templating: { engines: ['twig'] } session: ~
El otro cambio necesario consiste en eliminar la opción secure_controllers
del
servicio jms_security_extra
:
Configuración original de 2.0:
# app/config/config.yml jms_security_extra: secure_controllers: false secure_all_services: false
Nueva configuración de 2.1:
# app/config/config.yml jms_security_extra: secure_all_services: false
Si después de estos cambios se sigue produciendo algún error, busca en el documento UPGRADE la opción que te está causando problemas y consulta también la documentación de todos los bundles que utilices.
Actualizar las entidades
Los dos componentes de Symfony 2.1 que más cambios han sufrido desde la versión 2.0 son los formularios y el validador. Como las entidades de Doctrine casi siempre incluyen información de validación, comprueba si utilizas alguna de las siguientes validaciones que han cambiado:
Validación 2.0 Validación 2.1 --------------------------------- ---------------------------------- `@Assert\Size(min = 2, max = 16)` `@Assert\Range(min = 2, max = 16)` `@Assert\Min(2)` `@Assert\Range(min = 2)` `@Assert\Max(2)` `@Assert\Range(max = 2)` `@Assert\MinLength(8)` `@Assert\Length(min = 8)` `@Assert\MaxLength(8)` `@Assert\Length(max = 8)`
Si la entidad representa a un usuario, seguramente emplearás la interfaz
UserInterface
para integrarla fácilmente con el componente de seguridad de
Symfony2. Esta interfaz se ha simplificado en Symfony 2.1, por lo que puedes
eliminar el siguiente método equals()
:
public function equals(UserInterface $usuario) { return $this->getEmail() == $usuario->getEmail(); }
Actualizar los formularios
Si en tu aplicación haces un uso muy avanzado de los formularios, vas a tener que dedicar mucho tiempo a su actualización a Symfony 2.1. Además, es posible que algunos cambios ni siquiera estén bien documentados en el documento UPGRADE.
Por el contrario, si haces un uso normal de los formularios de Symfony 2.0, no te
costará apenas esfuerzo actualizarlos a Symfony 2.1. El primer cambio importante
se refiere a los argumentos del método buildForm()
:
Formularios Symfony 2.0:
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilder; class UsuarioType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { // ... } }
Formularios Symfony 2.1:
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; class UsuarioType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { // ... } }
Si el formulario está relacionado con una entidad de Doctrine, ahora es obligatorio
definir la opción data_class
que indica el namespace del objeto que se manipula
a través del formulario:
// ... use Symfony\Component\OptionsResolver\OptionsResolverInterface; class UsuarioType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { // ... } public function getName() { // ... } public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'Cupon\UsuarioBundle\Entity\Usuario', )); } }
Por último, también ha cambiado el método más importante de los que se utilizan
al procesar el formulario en un controlador: bindRequest()
ahora se llama
bind()
:
Formularios Symfony 2.0:
class DefaultController extends Controller { public function registroAction() { // ... if ($peticion->getMethod() == 'POST') { $formulario->bindRequest($this->getRequest()); // ... } // ... } }
Formularios Symfony 2.1:
class DefaultController extends Controller { public function registroAction() { // ... if ($peticion->getMethod() == 'POST') { $formulario->bind($this->getRequest()); // ... } // ... } }
Para todos los demás cambios relacionados con los formularios, no olvides consultar el documento UPGRADE.
Actualizar los tests
Los tests unitarios y funcionales no han sufrido ningún cambio, pero lógicamente deben adaptarse a los cambios del resto de componentes de Symfony2. Si por ejemplo tus tests hacen uso del validador, ha cambiado la forma de obtenerlo:
Obtener el validador en los tests de Symfony 2.0:
use Symfony\Component\Validator\ValidatorFactory; $this->validator = ValidatorFactory::buildDefault() ->getValidator();
Obtener el validador en los tests de Symfony 2.1:
use Symfony\Component\Validator\Validation; $this->validator = Validation::createValidatorBuilder() ->enableAnnotationMapping() ->getValidator();
Lamentablemente no es posible crear una guía de actualización de los tests,
así que tendrás que ir corrigiendo poco a poco todos los errores que se muestren
al ejecutar phpunit -c app
hasta que por fin veas la barra verde que significa
que ya no hay errores.
Otros cambios
Los cambios explicados en este artículo se pueden considerar como obligatorios ya que es casi seguro que todas las aplicaciones Symfony 2.0 deben hacerlos. No obstante, en tu aplicación seguramente tendrás que hacer algunos cambios más. Para ello, no olvides tener siempre a mano el documento UPGRADE.
¿Has visto algún error?
Avísanos en [email protected] para que podamos corregirlo. Gracias.
Proyectos Symfony destacados
La forma más sencilla de generar el backend de tus aplicaciones Symfony. Ver más
Síguenos en @symfony_es para acceder a las últimas noticias.