Más con Symfony

13.8. Refactorizando las tareas

Como enviar emails (y crear su contenido) y generar URL son dos actividades muy comunes, puede ser una buena idea crear una tarea base que proporcione estas dos características a cualquier tarea que las necesite. Para conseguirlo, crea una clase base en tu proyecto en el archivo lib/task/sfBaseEmailTask.class.php.

class sfBaseEmailTask extends sfBaseTask
{
  protected function registerDecorator($replacements)
  {
    $this->getMailer()->registerPlugin(new Swift_Plugins_DecoratorPlugin($replacements));
  }

  protected function getMessageBody($template, $vars = array())
  {
    $engine = $this->getTemplateEngine();
    return $engine->render($template, $vars);
  }

  protected function getTemplateEngine($replacements = array())
  {
    if (is_null($this->templateEngine))
    {
      $loader = new sfTemplateLoaderFilesystem(sfConfig::get('sf_app_template_dir').'/templates/emails/%s.php');
      $this->templateEngine = new sfTemplateEngine($loader);
    }

    return $this->templateEngine;
  }
}

Ya que estamos en ello, vamos a automatizar también la creación de las opciones de la tarea. Para ello, añade los siguientes métodos en la clase sfBaseEmailTask:

public function configure()
{
  $this->addOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application', 'frontend');
}

protected function generateUrl($route, $params = array())
{
  return $this->getRouting()->generate($route, $params, true);
}

Utilizando el método configure() se pueden añadir opciones comunes a todas las tareas que hereden de esta clase. El único inconveniente es que cualquier clase que herede de sfBaseEmailTask obligatoriamente tendrá que invocar el método parent::configure dentro de su propio método configure(). De todas formas, se trata de un inconveniente menor en comparación de todo lo que se gana a cambio.

Vamos a refactorizar a continuación el código de acceso a la internacionalización que se utilizó en la sección anterior:

public function configure()
{
  $this->addOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application', 'frontend');
  $this->addOption('culture', null, sfCommandOption::PARAMETER_REQUIRED, 'The culture', 'en');
}

protected function getI18N()
{
  if (!$this->i18n)
  {
    $config = sfFactoryConfigHandler::getConfiguration($this->configuration->getConfigPaths('config/factories.yml'));
    $class  = $config['i18n']['class'];

    $this->i18n = new $class($this->configuration, null, $config['i18n']['param']);

    $this->i18n->setCulture($this->commandManager->getOptionValue('culture'));
  }

  return $this->i18n;
}

protected function changeCulture($culture)
{
  $this->getI18N()->setCulture($culture);
}

protected function process(sfCommandManager $commandManager, $options)
{
  parent::process($commandManager, $options);
  $this->commandManager = $commandManager;
}

El problema que debemos resolver es que no se pueden acceder a las opciones y argumentos fuera del contexto del método execute(). Por tanto, se redefine el método process() para incluir el gestor de opciones dentro de la clase. El gestor de opciones se encarga, como su propio nombre indica, de gestionar los argumentos y opciones de la tarea. Para obtener por ejemplo el valor de una opción, se utiliza el método getOptionValue().