Parametrizando nuestro sistema con symfony 2/2

Continúo con lo prometido de seguir con el artículo Parametrizando nuestro sistema con symfony con este segundo artículo sobre esta serie. Aquí veremos como implementar con Symfony unos métodos que nos hagan un poco más sencillo el desarrollo de una aplicación parametrizada.

Habíamos visto en el artículo anterior que podríamos trabajar creando una tabla en la que centralicemos los parámetros de nuestra aplicación según dos puntos importantes.

  1. Cantidad de registros: Si la cantidad de registros es relativamente fija y no crecen tan variablemente como son las tablas transaccionales.
  2. Cantidad de columnas: Si estas tablas tienen exactamente 2 columnas como generalmente serían id y nombre.

De esta manera lograríamos no tener tantas tablas que simplemente las usamos como parámetro y hacer nuestra aplicación mucho mas fácil de mantener.

En éste artículo veremos como manipular los datos de la tabla parámetro de una forma en la que no necesitemos mucha conversación con la base de datos.

En primer lugar lo que necesitamos es un método que nos devuelva los datos de la tabla parámetro en un array lo cual, con ayuda de Doctrine, lo haríamos con el código de abajo, agregando un método al a clase ParametroTable.

class ParametroTable extends Doctrine_Table
{

    /**
     * Obtiene todos los registros de la tabla parametro y
     * los retorna en forma de array
     * @see myUser::getOneParametro()
     * @see myUser::getParametrosForSelect()
     * @see myUser::getParametrosForSelectIn()
     * @see myUser::getParametrosForSelectNotIn()
     * @return array
     */
    public static function getAll()
    {

        $q = Doctrine_Query::create()
                        ->select('p.dominio, p.abreviatura, p.descripcion, p.orden')
                        ->from('Parametro p')
                        ->orderBy('p.dominio asc')
                        ->addOrderBy('p.orden asc')
                        ->addOrderBy('p.descripcion asc');

        $parametros = $q->fetchArray();

        return $parametros;
    }
}

Con este método lo único que tenemos que hacer, por ejemplo, dentro del login del usuario es poner la siguiente línea:

$this->getUser()->setAttribute('parametros', ParametroTable::getAll());

De esta manera, ya tenemos cargado el array con los parámetro dentro de la sesión del usuario activo y nos faltaría solo poder recuperar los datos, para lo que crearemos 4 métodos dentro del myUser ya que él es el encargado de trabajar con la sesión y es muy interesante mencionar que a partir de ahora ya no necesitamos más a la base de datos.

Para obtener un parámetro específico

/**
 * Obtiene un parametro de los que se encuentran guardados en la sesión del
 * usuario dependiendo del $dominio y $abreviatura recibidos.
 * @param string $dominio
 * @param string $abreviatura
 * @return string
 */
public function getOneParametro($dominio, $abreviatura)
{
    //-- Obtenemos el array almacenado en sesión.
    $parametros = $this->getAttribute('parametros');

    //-- recorremos el array en busqueda del dominio y abreviatura buscados
    //   en caso de haberlo encontrado retornamos la descripcion.
    for ($i = 0; $i < count($parametros); $i++)
    {
        if ($parametros[$i]['dominio'] == $dominio && $parametros[$i]['abreviatura'] == $abreviatura)
            return $parametros[$i]['descripcion'];
    }

    //-- En caso de no encontrarlo retornamos un texto para indicar que el
    //   parámetro no existe.
    return sprintf('Parametro (%s) no existe', $abreviatura);
}

Para obtener una lista de parámetros de acuerdo a un dominio específico

/**
 * Obtiene un array de parametros de la sesión del usuario para ser usaso en
 * un <select> de acuerdo al $dominio enviado.
 * Si $optional es true, cargará la primera posición  con un <option> vacío.
 * @param string $dominio
 * @param boolean $optional
 * @return array
 */
public function getParametrosForSelect($dominio, $optional = false)
{
    //-- Obtenemos el array almacenado en sesión.
    $parametros = $this->getAttribute('parametros');

    //-- creamos un array vacío en donde vamos a ir cargando
    //   los elementos encontrados.
    $ret = array();

    //-- En caso de haberse enviado el parametro $optional como true cargamos
    //   el primer elemento del array con un key vacio y un valor cualquiera
    if ($optional)
        $ret[''] = '--';

    //-- Recorremos el array en busqueda de todos los parámetros que pertenezcan
    //   al dominio enviado por parámetro.
    foreach($parametros as $parametro)
    {
        if ($parametro['dominio'] == $dominio)
            $ret[$parametro['abreviatura']] = $parametro['descripcion'];
    }

    //-- una vez que hemos cargado el array lo retornamos
    return $ret;
}

Para obtener una lista de parámetros de acuerdo a un dominio y una lista específica

/**
 * Obtiene un array de parametros de la sesión del usuario para ser usaso en
 * un <select> de acuerdo al $dominio enviado. Adicionalmente recibe un array
 * de abreviaturas $in utilizado para incluir solo las que se necesiten.
 * Si $optional es true, cargará la primera posición  con un <option> vacío.
 * @param string $dominio
 * @param array $in
 * @param boolean $optional
 * @return array
 */
public function getParametrosForSelectIn($dominio, $in, $optional = false)
{
    //-- Obtenemos los parametros del dominio enviado
    $parametros = $this->getParametrosForSelect($dominio, $optional);

    //-- Recorremos y sacamos las abreviaturas no enviadas dentro del $in
    foreach($parametros as $key => $value)
    {
        if($key !== '' && in_array($key, $in, true) === false)
            unset($parametros[$key]);
    }

    //-- Retornamos el array filtrado
    return $parametros;
}   

Para obtener una lista de parámetros de acuerdo a un dominio específico y una lista que excluya algunos

/**
 * Obtiene un array de parametros de la sesión del usuario para ser usaso en
 * un <select> de acuerdo al $dominio enviado. Adicionalmente recibe un array
 * de abreviaturas $in utilizado para incluir solo las que se necesiten.
 * Si $optional es true, cargará la primera posición  con un <option> vacío.
 * @param string $dominio
 * @param array $in
 * @param boolean $optional
 * @return array
 */
public function getParametrosForSelectNotIn($dominio, $in, $optional = false)
{
    //-- Obtenemos los parametros del dominio enviado
    $parametros = $this->getParametrosForSelect($dominio, $optional);

    //-- Recorremos y sacamos las abreviaturas no enviadas dentro del $in
    //   exceptuamos al key vacío para el caso que $optional valga true
    foreach($parametros as $key => $value)
    {
        if(in_array($key, $in, true))
            unset($parametros[$key]);
    }

    //-- Retornamos el array filtrado
    return $parametros;
}

Esto lo podemos utilizar dentro de nuestros actions utilizando $this->getUser() y en los templates con $sf_user de la siguiente manera:

$this->getUser()->setAttribute('parametros', ParametroTable::getAll());

$p = $this->getUser()->getOneParametro('ESTADO_ARTICULO', 'B');
//-- Borrador

$p = $this->getUser()->getParametrosForSelect('ESTADO_ARTICULO');
//-- Array ( [B] => Borrador [EV] => En verificación [PUB] => Publicado [X] => Borrado ) 

$p = $this->getUser()->getParametrosForSelect('ESTADO_ARTICULO', true);
//-- Array ( [] => -- [B] => Borrador [EV] => En verificación [PUB] => Publicado [X] => Borrado )

$p = $this->getUser()->getParametrosForSelectIn('ESTADO_ARTICULO', array('EV', 'PUB'), true);
//-- Array ( [] => -- [EV] => En verificación [PUB] => Publicado )

$p = $this->getUser()->getParametrosForSelectNotIn('ESTADO_ARTICULO', array('EV', 'PUB'));
//-- Array ( [B] => Borrador [X] => Borrado )

Es importante tener en cuenta que fuera de estos dos lugares (action y template), tendremos que acceder al objeto sfUser a través de la ruta larga: sfContext::getInstance()->getUser().

En este punto ya podemos ver como tenemos acceso a los parámetros directamente de la sesión del usuario, pero ahora nos queda ver como mostrarlos como un combo dentro de un formulario. Para esto podemos usar cualquier de los últimos tres métodos que creamos en la clase myUser. Veamos un ejemplo:

class TestForm extends BaseForm
{

    public function configure()
    {
        //-- Obtengo la lista de estados del usuario, permitiendo que la primera opción este vacía.
        $estadoUsuarioOptions = sfContext::getInstance()->getUser()->getParametrosForSelect('ESTADO_USUARIO', true);

        //-- Creo el combo para estados
        $this->setWidgets(array(
            'estado' => new sfWidgetFormSelect(array('choices' => $estadoUsuarioOptions)),
        ));

        //-- Asigno el nombre del formulario
        $this->widgetSchema->setNameFormat('test[%s]');

        //-- Agrego los validadores
        $this->setValidators(array(
            //-- El validador del combo sería que solo pueden llegar valores
            //   contenidos dentro de los estados previstos.
            'estado' => new sfValidatorChoice(
                    array(
                        'required' => true,
                        'choices' => array_keys($estadoUsuarioOptions),
                    ),
                    array(
                        'required' => 'Debe seleccionar un estado',
                        'invalid' => 'Valores incorrectos',
            )),
        ));

    }

}

De esta manera tengo la posibilidad de obtener para el formulario los valores que los combos puedan tener y también las validaciones con el mismo array obtenido de la sesión y ya no tengo la necesidad de ejecutar un query a la base de datos.

Solo como comentario, en JAVA utilizando el JBOSS como servidor de aplicaciones, tenemos un contexto llamado de aplicación que es como una sesión compartida entre los usuarios, que se reinicia cada vez que el servidor es reiniciado. Lo ideal sería almacenar el array parámetros dentro de este contexto pero no lo he visto nunca con PHP así que será una buena investigación para continuar con esta serie.

Espero que les haya sido de utilidad y que den sus opiniones sobre el tema, con ayuda de ustedes podríamos llegar a hacer algo aún más interesante.

Hasta la próxima.

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

Comenta este artículo