Actualización de Symfony 1.2 a Symfony 1.3 / 1.4

Este tutorial describe los cambios que se deben realizar en los proyectos creados con Symfony 1.2 para que sigan funcionando correctamente al actualizar a Symfony 1.3/1.4.

Si quieres conocer todos los cambios introducidos por Symfony 1.3/1.4, puedes leer el tutorial Las novedades de Symfony 1.3 y 1.4.

Cuidado

Symfony 1.3/1.4 es compatible con PHP 5.2.4 o superior. Podrían funcionar también con las versiones comprendidas entre PHP 5.2.0 y 5.2.3, pero no hay ninguna garantía de que así sea.

Actualizando a Symfony 1.4

Symfony 1.4 no dispone de una tarea de actualización porque en realidad es la misma versión que Symfony 1.3 a la que se le han quitado todos los elementos declarados obsoletos. Por tanto, para actualizar a la versión 1.4 primero tienes que actualizar a la versión 1.3 y después ya puedes actualizar a Symfony 1.4.

Antes de realizar la actualización a 1.4, puedes utilizar la tarea project:validate para asegurarte de que tu proyecto no utiliza ninguna clase, método, función u opción declarada obsoleta:

$ php symfony project:validate

Esta tarea muestra como resultado todos los archivos que debes modificar antes de poder actualizar a Symfony 1.4.

Debes tener en cuenta que esta tarea basa su funcionamiento en expresiones regulares y por tanto se pueden producir falsos positivos. Además no puede detectar todos los posibles casos, así que se trata de una herramienta que te ayuda a identificar posibles problemas, pero no es una herramienta mágica infalible. Así que te recomendamos que leas el tutorial de todos los elementos declarados obsoletos por Symfony 1.4.

Nota

Los plugins sfCompat10Plugin y sfProtoculousPlugin se han eliminado en Symfony 1.4. Si los has deshabilitado explícitamente en las clases de configuración del proyecto (por ejemplo en config/ProjectConfiguration.class.php), debes eliminar incluso esa referencia.

Actualizando a Symfony 1.3

La actualización a Symfony 1.3 de un proyecto creado con Symfony 1.2 comprende los siguientes pasos:

1) Comprueba que todos los plugins que utiliza tu proyecto son compatibles con Symfony 1.3.

2) Si no utilizas una herramienta de control de código fuente (tipo git o Subversion), haz una copia de seguridad del proyecto.

3) Actualiza Symfony a su versión 1.3

4) Actualiza los plugins a su versión compatible con Symfony 1.3

5) Ejecuta la tarea project:upgrade1.3 desde el directorio raíz de tu proyecto para que se realice una actualización automática. Esta tarea se puede ejecutar varias veces seguidas sin efectos adversos:

$ php symfony project:upgrade1.3

6) Vuelve a construir tus modelos y formularios para que tengan en cuenta los cambios que se explican más adelante:

# En Doctrine
$ php symfony doctrine:build --all-classes
 
# En Propel
$ php symfony propel:build --all-classes

7) Borra la cache:

$ php symfony cache:clear

Las siguientes secciones explican los principales cambios introducidos en Symfony 1.3 que requieren una actualización manual o automática.

Elementos declarados obsoletos

Durante el desarrollo de Symfony 1.3 se han eliminado y/o declarado obsoletas algunas opciones de configuración, clases, métodos, funciones y tareas. Puedes consultar todos ellos detalladamente en el tutorial Elementos declarados obsoletos en Symfony 1.3.

Carga automática de clases

Desde Symfony 1.3 los archivos que se encuentran bajo el directorio lib/vendor/ ya no se cargan automáticamente. Si quieres cargar de forma automática algunos subdirectorios de lib/vendor/, añade una nueva entrada en el archivo de configuración autoload.yml de la aplicación:

autoload:
  vendor_mi_libreria:
    name:      vendor_mi_libreria
    path:      %SF_LIB_DIR%/vendor/directorio_mi_libreria
    recursive: on

La carga automática de archivos de lib/vendor/ presentaba los siguientes problemas:

  • Si guardas en lib/vendor/ una librería que dispone de su propio mecanismo de carga automática de clases, Symfony vuelve a procesar todos los archivos y añade un montón de información inútil en la cache.
  • Si el directorio donde guardas Symfony no se llama exactamente lib/vendor/symfony/, el cargador automático de clases del proyecto vuelve a procesar todo el directorio de Symfony y se pueden producir errores.

Además, la carga automática de clases de Symfony 1.3 ya no distingue mayúsculas de minúsculas.

Enrutamiento

Los métodos sfPatternRouting::setRoutes(), sfPatternRouting::prependRoutes(), sfPatternRouting::insertRouteBefore() y sfPatternRouting::connect() ya no devuelven las rutas como un array, tal y como hacían en las versiones anteriores.

La opción lazy_routes_deserialize se ha eliminado porque ya no es necesaria.

Desde Symfony 1.3 la cache del enrutamiento está desactivada, ya que se trata de la mejor opción para la mayoría de proyectos en lo que respecto al rendimiento. Así que si no has modificado la cache del enrutamiento, se desactivará automáticamente para todas tus aplicaciones. Si después de actualizar a Symfony 1.3 tu proyecto se ejecuta más lentamente, puedes probar a activar la cache del enrutamiento. A continuación se muestra la antigua configuración por defecto de Symfony 1.2 por si debes añadirla de nuevo en el archivo factories.yml:

routing:
  param:
    cache:
      class: sfFileCache
      param:
        automatic_cleaning_factor: 0
        cache_dir:                 %SF_CONFIG_CACHE_DIR%/routing
        lifetime:                  31556926
        prefix:                    %SF_APP_DIR%/routing

Archivos JavaScript y hojas de estilos

Eliminación del filtro común

El filtro sfCommonFilter se ha declarado obsoleto y ya no se utiliza por defecto. Este filtro se usaba para enlazar de forma automática los archivos JavaScript y las hojas de estilos utilizados en la página. Ahora debes incluir de forma explícita este tipo de archivos mediante llamadas a los helpers include_stylesheets() y include_javascripts() en tu layout:

<?php include_javascripts() ?>
<?php include_stylesheets() ?>

Las razones por las que se ha eliminado son las siguientes:

  • Se dispone de una solución mejor, más sencilla y más flexible (los helpers include_stylesheets() y include_javascripts())
  • Aunque el filtro común se puede desactivar, no es algo intuitivo porque primero hay que ser consciente de su existencia y de su funcionamiento mágico
  • Utilizar los helpers permite un control más precio de los archivos que se incluyen en el layout y de dónde se incluyen (las hojas de estilos dentro de la etiqueta <head> y los archivos de JavaScript justo antes de la etiqueta </body> de cierre)
  • Siempre es mejor ser explícito y no implícito (mejor no utilizar tanta magia y provocar tantos quebraderos de cabeza a los usuarios)
  • Mejora ligeramente el rendimiento

¿Cómo se actualiza?

  • Se debe eliminar el filtro common de todos los archivos de configuración filters.yml (lo modificar automáticamente la tarea project:upgrade1.3)
  • Se deben añadir llamadas a include_stylesheets() y include_javascripts() en tus layouts para obtener el mismo comportamiento que antes. Este cambio también lo realiza automáticamente la tarea project:upgrade1.3 para todos aquellos layouts HTML que se encuentren en directorios templates/ de tu aplicación y que contengan una etiqueta <head>. Debes modificar manualmente cualquier otro layout que no cumpla las condiciones anteriores o cualquier página que no tenga un layout pero que incluya archivos JavaScript y hojas de estilos
Nota

La clase sfCommonFilter todavía se incluye en Symfony 1.3, por lo que todavía puedes utilizarla en tus archivos filters.yml si lo necesitas.

Tareas

Se han renombrado las siguientes clases de las tareas:

Symfony 1.2 Symfony 1.3
sfConfigureDatabaseTask sfDoctrineConfigureDatabaseTask o sfPropelConfigureDatabaseTask
sfDoctrineLoadDataTask sfDoctrineDataLoadTask
sfDoctrineDumpDataTask sfDoctrineDataDumpTask
sfPropelLoadDataTask sfPropelDataLoadTask
sfPropelDumpDataTask sfPropelDataDumpTask

El uso de las tareas *:data-load se ha modificado, por lo que ahora se deben indicar como argumentos los archivos o directorios específicos. Además, la opción --dir se ha eliminado.

$ php symfony doctrine:data-load data/fixtures/dev

Formateadores

Se ha eliminar el tercer argumento del método sfFormatter::format().

Mecanismo de escape

El método esc_js_no_entities(), utilizado por ESC_JS_NO_ENTITIES, se ha actualizado para que procese correctamente los caracteres que no sean de tipo ANSI. Antes de este cambio, se escapaban todos los caracteres salvo los que tienen un valor ANSI de entre 37 y 177. Ahora sólo aplica el mecanismo de escape a las contrabarras \, comillas ‘ y " y los saltos de línea \n y \r. No obstante, es muy improbable que este cambio afecte a tus aplicaciones.

Integración con Doctrine

Versión de Doctrine requerida

Las referencias externas con el proyecto Doctrine se han actualizado para utilizar su versión 1.2 más reciente. Puedes leer sobre las novedades que incluye Doctrine 1.2 en su propio tutorial de actualización: http://www.doctrine-project.org/upgrade/1_2

Borrado en la parte de administración

El borrado masivo de la parte de administración se ha modificado para que primero obtenga los registros y después los borre individualmente con el método delete() de cada registro, en vez de utilizar una consulta DQL para borrarlos todos a la vez.
El motivo del cambio es que de esta forma se puede notificar el evento de borrado para cada registro individual.

Redefinir los esquemas Doctrine de los plugins

Se pueden redefinir los modelos de datos de los plugins simplemente definiendo ese mismo modelo en tu esquema de datos local. Si por ejemplo quieres añadir una columna llamada email en el modelo sfGuardUser del plugin sfDoctrineGuardPlugin, puedes añadir lo siguiente en tu archivo config/doctrine/schema.yml:

sfGuardUser:
  columns:
    email:
      type: string(255)
Nota

La opción package es una característica de Doctrine y se utiliza en los esquemas de los plugins de Symfony. Esto no significa que la característica package pueda utilizarse libremente para empaquetar tus modelos. De hecho, solamente se puede utilizar en los plugins de Symfony.

Mensajes de log de las consultas

Los mensajes de log de las consultas de Doctrine se notifican mediante el uso de sfEventDispatcher en lugar de acceder al objeto logger directamente. Además, la variable subject de estos eventos es o la conexión o la sentencia que está ejecutando la consulta. Los mensajes de log se generan mediante la clase sfDoctrineConnectionProfiler, que se puede acceder a través de un objeto de tipo sfDoctrineDatabase.

Plugins

Si en la clase ProjectConfiguration utilizas el método enableAllPluginsExcept() para controlar los plugins habilitados, debes tener en cuenta que ahora se ordenan los plugins en función de su nombre para asegurar la consistencia en las diferentes plataformas.

Widgets

La clase sfWidgetFormInput ahora es abstracta. Los campos de formulario de tipo texto ahora se crean con la clase sfWidgetFormInputText. Este último cambio se ha realizado para facilitar la introspección de las clases.

Mailer

Symfony 1.3 dispone de una nueva factoría de tipo mailer. Cuando se crea una nueva aplicación, el archivo factories.yml define algunas opciones de configuración lógicas para los entornos test y dev. Sin embargo, si estás actualizando un proyecto puede que no tengas esas mismas opciones de configuración, por lo que a continuación se muestra la configuración de factories.yml para el mailer de estos entornos:

mailer:
  param:
    delivery_strategy: none

La configuración anterior hace que los emails no se envíen de verdad, pero que si generen mensajes de log. Además, con las opciones anteriores también funciona el tester llamado mailer en las pruebas funcionales.

Si prefieres enviar todos los emails a una dirección de prueba, puedes utilizar la estrategia de envío single_address (por ejemplo en el entorno dev):

dev:
  mailer:
    param:
      delivery_strategy: single_address
      delivery_address:  destinatario@ejemplo.com

YAML

El componente sfYAML ahora es más compatible con la especificación 1.2 del estándar YAML. El principal cambio que debes realizar en tus archivos de configuración es que ahora los valores booleanos sólo se pueden representar mediante las cadenas de texto true o false. Si utilizas alguno de los valores que se muestran en las siguientes listas, debes reemplazarlos respectivamente por true o false:

  • on, y, yes, +
  • off, n, no, -

La tarea project:upgrade te indica dónde utilizas la sintaxis antigua pero no la corrige (para evitar la pérdida de los comentarios por ejemplo). Debes corregir estos valores a mano.

Si no quieres modificar todos tus archivos YAML, puedes forzar a que el procesador de archivos YAML utilice la especificación 1.1 del estándar. Para ello debes hacer uso del método sfYaml::setSpecVersion():

sfYaml::setSpecVersion('1.1');

Propel

Las antiguas clases constructoras propias de Propel se han sustituido por los nuevos behavior o comportamientos de Propel 1.4. Para aprovechar esta mejora, es imprescindible actualizar el archivo de configuración propel.ini.

Elimina las antiguas clases constructoras:

; builder settings
propel.builder.peer.class              = plugins.sfPropelPlugin.lib.builder.SfPeerBuilder
propel.builder.object.class            = plugins.sfPropelPlugin.lib.builder.SfObjectBuilder
propel.builder.objectstub.class        = plugins.sfPropelPlugin.lib.builder.SfExtensionObjectBuilder
propel.builder.peerstub.class          = plugins.sfPropelPlugin.lib.builder.SfExtensionPeerBuilder
propel.builder.objectmultiextend.class = plugins.sfPropelPlugin.lib.builder.SfMultiExtendObjectBuilder
propel.builder.mapbuilder.class        = plugins.sfPropelPlugin.lib.builder.SfMapBuilderBuilder

Y añade los nuevos behavior o comportamientos:

; behaviors
propel.behavior.default                        = symfony,symfony_i18n
propel.behavior.symfony.class                  = plugins.sfPropelPlugin.lib.behavior.SfPropelBehaviorSymfony
propel.behavior.symfony_i18n.class             = plugins.sfPropelPlugin.lib.behavior.SfPropelBehaviorI18n
propel.behavior.symfony_i18n_translation.class = plugins.sfPropelPlugin.lib.behavior.SfPropelBehaviorI18nTranslation
propel.behavior.symfony_behaviors.class        = plugins.sfPropelPlugin.lib.behavior.SfPropelBehaviorSymfonyBehaviors
propel.behavior.symfony_timestampable.class    = plugins.sfPropelPlugin.lib.behavior.SfPropelBehaviorTimestampable

La tarea project:upgrade intenta hacer este cambio automáticamente, pero puede que no sea posible hacerlo si has realizado algún cambio en el archivo propel.ini.

En Symfony 1.2 la clase BaseFormFilterPropel se generaba incorrectamente en el directorio lib/filter/base. En Symfony 1.3 se ha corregido este error y la clase ahora se genera en lib/filter. La tarea project:upgrade se encarga de mover la clase al directorio correcto.

Pruebas

El archivo de inicialización de las pruebas, test/bootstrap/unit.php, se ha actualizado para mejorar la carga automática de las clases del proyecto. La actualización consiste en añadir las siguientes líneas al script:

$autoload = sfSimpleAutoload::getInstance(sfConfig::get('sf_cache_dir').'/project_autoload.cache');
$autoload->loadConfiguration(sfFinder::type('file')->name('autoload.yml')->in(array(
  sfConfig::get('sf_symfony_lib_dir').'/config/config',
  sfConfig::get('sf_config_dir'),
)));
$autoload->register();

La tarea project:upgrade intenta hacer este cambio automáticamente, pero puede que no sea posible hacerlo si has realizado algún cambio en el archivo test/bootstrap/unit.php.