Extendiendo el sfActions de Symfony 2/3

Mensajes al usuario

Habiendo visto la primera parte de esta serie Extendiendo el sfActions de Symfony con el primer artículo, en el que vimos básicamente las primeras configuraciones que deberíamos hacer creando una clase BaseActions que extendiera de sfActions y haciendo que nuestros actions extiendan directamente de nuestra clase base, ahora podemos pasar a ver un ejemplo muy frecuente de uso, basándonos sobre el objeto myUser del cual hablamos en la serie Personalizando el objeto sfUser de Symfony.

Lo que hicimos en el myUser fue básicamente, para recordar, un método que permitiría cargar dentro del objeto Flash los mensajes de INFO, WARN y ERROR para los usuarios. Nos quedó algo así:

class myUser extends sfBasicSecurityUser
{
    const INFO_MESSAGE = 'infoMessages';
    const WARNING_MESSAGE = 'warnMessages';
    const ERROR_MESSAGE = 'errorMessages';
 
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    // METODOS PARA MANEJO DE MENSAJES FLASH
    //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 
    /**
     * Agrega mensajes al FLASH del objeto sfUser creando un array por cada tipo
     * de mensaje (myUser::INFO_MESSAGE, myUser::WARNING_MESSAGE, myUser::ERROR_MESSAGE).
     * El mensaje $msg será agregado al nivel correspondiente que por defecto será el INFO
     * @param string $msg
     * @param string $level
     */
    public function addMessage($msg, $level = myUser::INFO_MESSAGE)
    {
        //-- Obtengo el array almacenado, en caso de no existir retorna una array vacío
        $flashContent = $this->getFlash($level, array());
 
        //-- Controla si ya existe un mensaje igual para no insertarlo repetido
        if(!in_array($msg, $flashContent))
        {
            //- Agrego el mensaje enviado en la siguiente posición disponible del array
            $flashContent[] = $msg;
 
            //-- Seteo el array al Flash nuevamente
            $this->setFlash($level, $flashContent);
        }
    }
}

Ahora podemos ingresar desde nuestros actions directamente así:

$this->getUser()->addMessage('Bienvenido usuario: John Doe');
$this->getUser()->addMessage('Registro grabado con éxito', myUser::INFO_MESSAGE);
$this->getUser()->addMessage('Usuario o clave inválida', myUser::WARNING_MESSAGE);
$this->getUser()->addMessage('No se puedo conectar a la base de datos', myUser::ERROR_MESSAGE);

Bueno, la idea es simplificar aún más esto y darle un poco de nuevas funcionalidades a nuestro BaseActions creado en el artículo anterior. Si nos fijamos las llamadas son las mismas con la única diferencia que tenemos que pasarle el nivel de mensaje, infoMessage, warnMessage, errorMessage, los cuales definimos como constantes públicas dentro del objeto myUser.

Vista esta pequeña diferencia lo que vamos a hacer es crear, en un inicio, tres métodos en el BaseActions cada uno para cargar los mensajes para cada tipo.

  • addInfoMessage()
  • addWarnMessage()
  • addErrorMessage()
/**
  * Utiliza el método addMessage del objeto myUser para cargar un
  * mensaje $msg de Información para el usuario.
  * @see myUser::addMessage()
  * @param string $msg
  */
 protected function addInfoMessage($msg)
 {
     $this->getUser()->addMessage($msg, myUser::INFO_MESSAGE);
 }
 
 /**
  * Utiliza el método addMessage del objeto myUser para cargar un
  * mensaje $msg de Información para el usuario.
  * @see myUser::addMessage()
  * @param string $msg
  */
 protected function addWarnMessage($msg)
 {
     $this->getUser()->addMessage($msg, myUser::WARNING_MESSAGE);
 }
 
 /**
  * Utiliza el método addMessage del objeto myUser para cargar un
  * mensaje $msg de Información para el usuario.
  * @see myUser::addMessage()
  * @param string $msg
  */
 protected function addErrorMessage($msg)
 {
     $this->getUser()->addMessage($msg, myUser::ERROR_MESSAGE);
 }

De esta manera podemos ahora simplemente dentro de los actions, en el lugar en donde procesamos el mensaje, escribir:

public function executeTest(sfWebRequest $request)
{
    $this->addInfoMessage('Registro grabado con éxito');
    $this->addWarnMessage('Usuario o clave inválida');
    $this->addErrorMessage('No se puedo conectar a la base de datos');
 
    $this->redirect('principal/anotherTest');
}

De esta manera encapsulamos la forma de llamar a los métodos del myUser dentro del BaseActions

Ahora, agreguemos una utilidad más. Si recuerdan el archivo app.yml ubicado en %PROJECT%/apps/%APP%/config/, nos permite agregar datos que nos sirvan de utilidad para toda la aplicación. Me parece sumamente importante parametrizar los mensajes de los usuarios dentro de este archivo pudiendo codificarlos, como ejemplo, de esta manera:

  • 1000 – 1999: Mensajes de Información
  • 2000 – 2999: Mensajes de Alerta
  • 3000 – 3999: Mensajes de Errores

Podríamos tener algo más o menos así dentro del app.yml

all:
  .info_messages:
    producto_guardado:        1000 - El producto [%s] fue guardado con éxito.
    bienvenido_usuario:       1001 - Bienvenido usuario %s.
 
  .warn_messages:
    usuario_clave_invalida:   2000 - Usuario o clave inválida.
 
  .error_messages:
    no_conexion:              3000 - No se pudo conectar con la base de datos.
    archivo_no_existe:        3001 - El archivo '%s' no existe en [%s].

De esta manera podemos acceder a ellos a través de la clave sfConfig utilizando la etiqueta que utilizamos concatenada al texto “app_”. También tenemos que tener en cuenta que tenemos la familia de la función sprintf de PHP para pasar parámetros para los “%s”, por lo tanto encapsulemos esto dentro de métodos que nos faciliten la vida dentro del BaseActions.

/**
 * Recibe un mensaje $label almacenado en el app.yml y lo obtiene, completando
 * los parámetros con el array $args.
 * @see addInfoAppMessage
 * @see addWarnAppMessage
 * @see addErrorAppMessage
 * @param string $msg
 * @param array $args
 * @return string
 */
private function getAppMessage($label, $args)
{
    //-- Obtenemos el mensaje del app.yml y con la función vsprintf le pasamos
    //   un array con los parámetros.
    return vsprintf(sfConfig::get('app_' . $label), $args);
}
 
/**
 * Agrega un mensaje $label del app.yml al array de Flash.
 * El método puede recibir más de un parámetro a fin de usarlo como parámetros
 * para el mensaje del app.yml
 * @see addAppMessage
 * @see addWarnAppMessage
 * @see addErrorAppMessage
 * @param string $label
 * @param string $args parámetros opcionales para el label del app.yml
 */
protected function addInfoAppMessage($label)
{
    //-- Obtenemos los parámetros que reciba el método y eliminamos el primero
    //   ya que corresponde al $label.
    $args = func_get_args();
    unset($args[0]);
 
    //-- Controlamos que existan más y en caso de que existan llamamos al
    //   método privado BaseAction::getAppMessage() para que nos devuelva
    //   el texto generado. De lo contrario agregamos simplemente el label
    if(count($args))
        $this->addInfoMessage($this->getAppMessage($label, $args));
    else
        $this->addInfoMessage($label);
 
}
 
/**
 * Agrega un mensaje $label del app.yml al array de Flash.
 * El método puede recibir más de un parámetro a fin de usarlo como parámetros
 * para el mensaje del app.yml
 * @see addAppMessage
 * @see addInfoAppMessage
 * @see addErrorAppMessage
 * @param string $label
 * @param string $args parámetros opcionales para el label del app.yml
 */
protected function addWarningAppMessage($label)
{
    //-- Obtenemos los parámetros que reciba el método y eliminamos el primero
    //   ya que corresponde al $label.
    $args = func_get_args();
    unset($args[0]);
 
    //-- Controlamos que existan más y en caso de que existan llamamos al
    //   método privado BaseAction::getAppMessage() para que nos devuelva
    //   el texto generado. De lo contrario agregamos simplemente el label
    if(count($args))
        $this->addWarnMessage($this->getAppMessage($label, $args));
    else
        $this->addWarnMessage($label);
}
 
/**
 * Agrega un mensaje $label del app.yml al array de Flash.
 * El método puede recibir más de un parámetro a fin de usarlo como parámetros
 * para el mensaje del app.yml
 * @see addAppMessage
 * @see addInfoAppMessage
 * @see addWarningAppMessage
 * @param string $label
 * @param string $args parámetros opcionales para el label del app.yml
 */
protected function addErrorAppMessage($label)
{
    //-- Obtenemos los parámetros que reciba el método y eliminamos el primero
    //   ya que corresponde al $label.
    $args = func_get_args();
    unset($args[0]);
 
    //-- Controlamos que existan más y en caso de que existan llamamos al
    //   método privado BaseAction::getAppMessage() para que nos devuelva
    //   el texto generado. De lo contrario agregamos simplemente el label
    if(count($args))
        $this->addErrorMessage($this->getAppMessage($label, $args));
    else
        $this->addErrorMessage($label);
 
}

Ahora sí directamente para mostrar los mensajes podríamos llamarlos directo sin preocuparnos ni por el app.yml ni por los parámetros variables de la función sprintf.

public function executeTest(sfWebRequest $request)
{
    $this->addInfoAppMessage('producto_guardado', 'Monitor DELL');
    $this->addWarningAppMessage('usuario_clave_invalida');
    $this->addErrorAppMessage('archivo_no_existe', 'cuenta.xml', 'c:');
 
    $this->redirect('principal/anotherTest');
}

Bueno espero que les haya servido estos ejemplos y que puedan comentar que cosas les interesaría agregar al BaseActions. Espero sus aportes y sugerencias.

Los archivos de este artículos los puedes descargar aquí

Puedes ver el siguiente artículo sobre esta serie aquí.

Comenta este artículo