Symfony 1.1, la guía definitiva

16.3. Utilizando Symfony fuera de la web

En ocasiones, los scripts se ejecutan desde la línea de comandos o mediante una tarea programada. Muchas veces estos scripts deben tener acceso a todas las clases y características de Symfony, por ejemplo para enviar correos electrónicos de forma automática o para actualizar el modelo de datos mediante cálculos y operaciones complejas.

La forma más sencilla de crear un script de este tipo consiste en añadir al script las primeras líneas de los controladores frontales de Symfony para inicializar el framework. Además, estos scripts también pueden utilizar la línea de comandos de Symfony para aprovecharse del procesamiento de los argumentos y de la inicialización automática de la base de datos.

16.3.1. Archivos por lotes

La inicialización completa de Symfony se puede realizar con sólo unas pocas líneas de código PHP, tal y como muestra el listado 16-13.

Listado 16-13 - Ejemplo de archivo por lotes, en lib/miScript.php

<?php

require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'dev', true);
sfContext::createInstance($configuration);

// Borra las dos líneas siguientes si no utilizas una base de datos
$databaseManager = new sfDatabaseManager($configuration);
$databaseManager->loadConfiguration();

// A continuación añade tu propio código

Las líneas del listado anterior se parecen mucho a las primeras líneas de un controlador frontal (ver capítulo 6) porque son procesos similares: inicializar Symfony y procesar la configuración del proyecto y de la aplicación. El método ProjectConfiguration::getApplicationConfiguration() requiere tres parámetros:

  • El nombre de una aplicación
  • El nombre de un entorno de ejecución
  • Un valor booleano que indica si se activan o no las opciones de depuración de aplicaciones

Para ejecutar el script anterior sólo es necesario llamarlo desde la línea de comandos:

> php lib/miScript.php

16.3.2. Creando tareas propias

Una alternativa mejor a la creación de scripts y archivos por lotes es utilizar Symfony para crear nuevas tareas. De la misma forma que utilizas tareas como cache:clear y propel:build-model, puedes ejecutar tus propias tareas en la línea de comandos mediante php symfony. Las ventajas de las tareas propias es que pueden aprovechar el procesamiento de argumentos y opciones de la línea de comandos, pueden mostrar mensajes de ayuda sobre su uso y pueden ampliar las tareas existentes.

Una tarea propia es una clase que hereda de sfBaseTask y cuyo código se encuentra en el directorio lib/task/ de la raíz del proyecto o en el directorio lib/task de un plugin. La única restricción es que su nombre debe terminar en Task.class.php. El listado 16-14 muestra un ejemplo de tarea propia.

Listado 16-14 - Ejemplo de tarea, en lib/task/pruebaHolaMundoTask.class.php

class pruebaHolaMundoTask extends sfBaseTask
{
  protected function configure()
  {
    $this->namespace = 'prueba';
    $this->name = 'holaMundo';
    $this->briefDescription = 'Muestra un mensaje de saludo';
  }

  protected function execute()
  {
    // Aquí se incluye el código de la tarea
    $this->log('Hola mundo');
  }
}

El código que se incluye en el método execute() tiene acceso a todas las librerías de Symfony, como en el caso del script mostrado en la sección anterior. La principal diferencia se produce al ejecutar la tarea:

> php symfony prueba:holaMundo

El nombre de la tarea se forma con las propiedades namespace y name (que son de tipo protected) y no se tiene en cuenta el nombre de la clase ni el nombre de los archivos. Además, como la tarea se integra con la línea de comandos de Symfony, se muestra en el listado de tareas cuando se ejecuta el comando:

> php symfony

Si no quieres crear el esqueleto de la tarea manualmente, puedes utilizar la tarea generate:task. Esta tarea crea todo el código de una tarea vacía y dispone de muchas opciones para personalizar el código generado. Para acceder a sus opciones, simplemente ejecuta el siguiente comando:

> php symfony help generate:task

Las tareas pueden aceptar argumentos (parámetros obligatorios y en un orden determinado) y opciones (parámetros opcionales en los que tampoco importa su orden). El listado 16-15 muestra una tarea más compleja que hace uso de todas estas características.

Listado 16-15 - Ejemplo de tarea compleja, en lib/task/miSegundaTask.class.php

class miSegundaTask extends sfBaseTask
{
  protected function configure()
  {
    $this->namespace        = 'prueba';
    $this->name             = 'miSegundaTask';
    $this->briefDescription = 'Ejemplo de tarea compleja';
    $this->detailedDescription = <<<EOF
La tarea [prueba:miSegundaTask|INFO] realiza algunas cosas interesantes. La puedes ejecutar de la siguiente manera:

  [php symfony prueba:miSegundaTask frontend|INFO]

Puedes aumentar el nivel de detalle de los mensajes generados mediante la opción [verbose|COMMENT]:

  [php symfony prueba:miSegundaTask frontend --verbose=on|INFO]
EOF;
    $this->addArgument('aplicacion', sfCommandArgument::REQUIRED, 'El nombre de la aplicación');
    $this->addOption('verbose', null, sfCommandOption::PARAMETER_REQUIRED, 'Aumenta el nivel de detalle de los mensajes generados', false);
  }

  protected function execute($arguments = array(), $options = array())
  {
    // Aquí se incluye el código de la tarea

  }
}

Nota Si tu tarea quiere acceder a una base de datos, su clase debe heredar de sfPropelBaseTask en vez de sfBaseTask. De esta forma, la inicialización de la tarea tiene en cuenta que debe cargar todas las clases de Propel. Para crear una conexión con la base de datos en el método execute() ejecuta la siguiente instrucción:

$databaseManager = new sfDatabaseManager($this->configuration);

Si la configuración de la tarea define los argumentos application y env, se tienen en cuenta automáticamente cuando se construye la configuración de la tarea, por lo que una tarea puede utilizar cualquiera de las conexiones con bases de datos definidas en el archivo databases.yml. Las tareas vacías creadas con la tarea generate:task incluyen esta inicialización por defecto.

Una buena forma de descubrir las posibilidades de las tareas consiste en ver el código fuente de las propias tareas de Symfony.

Si creas una tarea con el mismo nombre que alguna tarea existente, tu clase redefine la clase existente. Por lo tanto, un plugin puede redefinir las tareas de Symfony y un proyecto puede redefinir tanto las tareas de Symfony como las tareas de los plugins. Si además se tiene en cuenta que una tarea puede heredar de otra tarea, se comprueba que el mecanismo de línea de comandos de Symfony es realmente flexible.