Tabla de contenidos
Un maestro-detalle es el caso de una ventana con paneles dependientes, este caso no se diferencia mucho de una ventana normal de gvHidra aunque tiene sus peculiaridades.
Al igual que en las ventanas "normales", en primer lugar se debe crear una clase por cada uno de los paneles que aparezcan en la pantalla, es decir, una clase para el maestro y una para el detalle. Como siempre estas clases se depositarán en el directorio actions de la estructura de la aplicación.
Las clases, tanto la del maestro como la del detalle, son como cualquier clase de un panel, tal y como se ha explicado en el punto 3.2.2 Paso a paso, salvo unas anotaciones:
Clase manejadora del maestro.
Un panel que tenga otro/s panel/es dependiente/s tendrán que utilizar el método addHijo() en el constructor de la clase. A este método se le pasan tres parámetros, el primero es el nombre de la clase hija, el segundo y tercer parámetro son dos arrays que definirán por qué campos se establece la relación entre maestro y detalle. El segundo es un array con los campos del padre que van a ser utilizados para recargar el hijo, y el tercer parámetro, un array con el nombre de los campos del detalle que se corresponden con los del maestro.
class TinvTipos extends gvHidraForm_DB
{
function TinvTipos()
{
...
$this->addHijo("TinvSubtipos",array("lisCodigoTipo"),array("ediCodigoTipo"));
...
}
}
Por ejemplo, tenemos que crear un mantenimiento para dos tablas: tipos y subtipos. Estas tablas tienen una relación 1:N (por cada tipo pueden haber N subtipos). Implementado en gvHidra, tendremos dos clases en el directorio actions (p.e. TinvTipos y TinvSubtipos). La clase TinvTipos tiene un hijo que se llama TinvSubtipos. El campo de la tpl ediCodigoTipo (en el panel maestro), se utiliza para identificar a los subtipos (los detalles) y en el panel detalle existe un campo que hace referencia al campo del maestro y cuyo nombre es lisCodigoTipo.
Clase manejadora del detalle.
Igual que en el maestro, el detalle también tiene que tener una referencia a su padre. Concretamente se debe utilizar el método addPadre() en el constructor de la clase, donde se le pasará como parámetro el nombre de la clase que maneja el panel maestro. Por tanto, siguiendo con nuestro ejemplo, la clase TinvSubtipos debe incorporar la siguiente línea:
class TinvSubtipos extends gvHidraForm_DB
{
function TinvSubtipos()
{
...
$this->addPadre("TinvTipos");
...
}
}
El siguiente cambio respecto a las ventanas "normales" viene en la creación de los paneles en los ficheros ubicados en el directorio views. Deberemos definir los dos paneles, maestro y detalle, a partir de la clase IgepPanel. Una vez definidos debemos utilizar el método de la clase IgepPantalla, agregarPanelDependiente(), para agregar el panel detalle al maestro. A este método se le han de pasar dos parámetros, el primero debe ser el panel a agregar y, el segundo, el nombre de la clase que maneja el panel padre. El fichero de views podría quedar así:
<?php $comportamientoVentana = new IgepPantalla(); // Definición del MAESTRO $panelMaestro = new IgepPanel('TinvTipos',"smty_datosTablaM"); $panelMaestro->activarModo("fil","estado_fil"); $panelMaestro->activarModo("lis","estado_lis"); $comportamientoVentana->agregarPanel($panelMaestro); // Definición del DETALLE $panelDetalle = new IgepPanel('TinvSubtipos',"smty_datosFichaD"); $panelDetalle->activarModo("edi","estado_edi"); // Agregamos el panel detalle al maestro $comportamientoVentana->agregarPanelDependiente($panelDetalle,"TinvTipos"); $s->display('tablasMaestras/p_tiposubtipo.tpl'); ?>
Finalmente, en la plantilla (tpl) para un maestro detalle también tiene algunas características que destacar de una plantilla para una ventana sencilla. Vamos a ver los puntos:
Hay que indicar que es un panel maestro con el atributo esMaestro del plugin CWPanel (esMaestro="true")
El parámetro itemSeleccionado del plugin CWPanel es un parámetro interno para el correcto funcionamiento de gvHidra, por eso se asigna a una variable smarty, itemSeleccionado=$smty_filaSeleccionada, para mantener el maestro seleccionado.
El botón tooltip (CWBotonTooltip) para insertar registros en el maestro tiene un parámetro ocultarMD con el que le indicamos qué panel se debe ocultar cuando pasamos a modo inserción, ya que va a ser un registro nuevo del maestro por lo tanto aún no tiene detalle.
En el plugin CWContenedorPestanyas se tiene que indicar con el parámetro id si las pestañas son del maestro o del detalle.
Las pestañas del panel maestro (CWPestanya) tienen unos parámetros, mostrar y ocultar, con los que se indicará si el panel detalle lo queremos visible o no. Además está el parámetro panelAsociado donde se indica a qué panel se refiere esa pestaña, ya que vamos a tener pestañas tanto para el maestro como para el detalle.
Llegamos a la parte de definir el detalle, establecemos una condición con sintaxis de smarty {if count($smty_datosTablaM) gt 0}, para que no nos muestre el panel detalle si no hay datos en el maestro.
El identificador, id, que le demos al panel del detalle (CWPanel) deberá ser lisDetalle, en el caso de estar en un modo tabular, o ediDetalle, en modo registro. También hay que indicar el parámetro detalleDe pasándole el id del maestro.
Tanto si el detalle es una ficha (CWFichaEdicion) como un tabular (CWTabla) hay que definir su id, FichaDetalle o TablaDetalle, respectivamente.
En el panel del detalle es necesario definir el o los campos que contengan la clave del maestro. En el siguiente ejemplo tenemos un maestro-detalle, siendo la clave del maestro el campo "lisCodigoTipo", el detalle necesita del valor de este campo, para ello vemos que en el panel del detalle tenemos un campo "ediCodigoTipo", que será el que nos relacione el detalle con su maestro. Para que el campo del detalle tenga el valor de la clave del maestro hay que definir su propiedad value, en el ejemplo value=$defaultData_TinvSubtipos.ediCodigoTipo.
Si nos encontramos en el caso de un detalle "Tabular-Registro" hay que definir estos campos clave tanto para el panel tabular como para el panel registro.
{CWVentana tipoAviso=$smty_tipoAviso codAviso=$smty_codError descBreve=$smty_descBreve textoAviso=$smty_textoAviso onLoad=$smty_jsOnLoad} {CWBarra usuario=$smty_usuario codigo=$smty_codigo customTitle=$smty_customTitle} {CWMenuLayer name="$smty_nombre" cadenaMenu="$smty_cadenaMenu"} {/CWBarra} {CWMarcoPanel conPestanyas="true"} <!-- *********************** PANEL MAESTRO ***********************--> <!--*********** PANEL fil ******************--> {CWPanel id="fil" action="buscar" method="post" estado=$estado_fil claseManejadora="TinvTipos"} {CWBarraSupPanel titulo="Tipos de Bienes"} {CWBotonTooltip imagen="04" titulo="Limpiar Campos" funcion="limpiar" actuaSobre="ficha"} {/CWBarraSupPanel} {CWContenedor} {CWFicha} <br /> {CWCampoTexto nombre="filCodigoTipo" editable="true" size="2" textoAsociado="Código de Tipo" dataType=$dataType_TinvTipos.filCodigoTipo} <br /><br /> {CWCampoTexto nombre="filDescTipo" editable="true" size="30" textoAsociado="Descripción de Tipo" dataType=$dataType_TinvTipos.filDescTipo} <br /><br /> {/CWFicha} {/CWContenedor} {CWBarraInfPanel} {CWBoton imagen="50" texto="Buscar" class="boton" accion="buscar"} {/CWBarraInfPanel} {/CWPanel} <!--*********** PANEL lis ******************--> {CWPanel id="lis" tipoComprobacion="envio" esMaestro="true" itemSeleccionado=$smty_filaSeleccionada action="operarBD" method="post" estado=$estado_lis claseManejadora="TinvTipos"} {CWBarraSupPanel titulo="Tipos de Bienes"} {CWBotonTooltip imagen="01" titulo="Insertar registros" funcion="insertar" actuaSobre="tabla" ocultarMD="Detalle"} {CWBotonTooltip imagen="02" titulo="Modificar registros" funcion="modificar" actuaSobre="tabla"} {CWBotonTooltip imagen="03" titulo="Eliminar registros" funcion="eliminar" actuaSobre="tabla"} {CWBotonTooltip imagen="04" titulo="Limpiar Campos" funcion="limpiar" actuaSobre="tabla"} {/CWBarraSupPanel} {CWContenedor} {CWTabla conCheck="true" conCheckTodos="false" id="Tabla1" numFilasPantalla="4" datos=$smty_datosTablaM} {CWFila tipoListado="false"} {CWCampoTexto nombre="lisCodigoTipo" editable="nuevo" size="2" textoAsociado="Cod.Tipo" dataType=$dataType_TinvTipos.lisCodigoTipo} {CWCampoTexto nombre="lisDescTipo" editable="true" size="25" textoAsociado="Tipo" dataType=$dataType_TinvTipos.lisDescTipo} {/CWFila} {CWPaginador enlacesVisibles="3"} {/CWTabla} {/CWContenedor} {CWBarraInfPanel} {CWBoton imagen="41" texto="Guardar" class="boton" accion="guardar"} {CWBoton imagen="42" texto="Cancelar" class="boton" accion="cancelar"} {/CWBarraInfPanel} {/CWPanel} <!-- ****************** PESTAÑAS ************************--> {CWContenedorPestanyas id="Maestro"} {CWPestanya tipo="fil" panelAsociado="fil" estado=$estado_fil ocultar="Detalle"} {CWPestanya tipo="lis" panelAsociado="lis" estado=$estado_lis mostrar="Detalle"} {/CWContenedorPestanyas} </td></tr> <tr><td> <!-- ****************** PANEL DETALLE ***********************--> {if count($smty_datosTablaM) gt 0} {CWPanel id="ediDetalle" tipoComprobacion="envio" action="operarBD" detalleDe="lis" method="post" estado="on" claseManejadora="TinvSubtipos"} {CWBarraSupPanel titulo="Subtipos de Bienes"} {CWBotonTooltip imagen="01" titulo="Insertar registros" funcion="insertar" actuaSobre="ficha"} {CWBotonTooltip imagen="02" titulo="Modificar registros" funcion="modificar" actuaSobre="ficha"} {CWBotonTooltip imagen="03" titulo="Eliminar registros" funcion="eliminar" actuaSobre="ficha"} {/CWBarraSupPanel} {CWContenedor} {CWFichaEdicion id="FichaDetalle" datos=$smty_datosFichaD} {CWFicha} <br /><br /> {CWCampoTexto nombre="ediCodigoSubtipo" editable="nuevo" size="3" textoAsociado="Código" dataType=$dataType_TinvSubtipos.ediCodigoSubtipo} <br /><br /> {CWCampoTexto nombre="ediDescSubtipo" editable="true" size="35" textoAsociado="Descripción" dataType=$dataType_TinvSubtipos.ediDescSubtipo} <br /><br /> {CWCampoTexto nombre="ediCodigoTipo" oculto="true" value=$defaultData_TinvSubtipos.ediCodigoTipo} {/CWFicha} {CWPaginador enlacesVisibles="3"} {/CWTabla} {/CWContenedor} {CWBarraInfPanel} {CWBoton imagen="41" texto="Guardar" class="boton" accion="guardar"} {CWBoton imagen="42" texto="Cancelar" class="boton" accion="cancelar"} {/CWBarraInfPanel} {/CWPanel} <!-- ****************** PESTAÑAS ************************--> {CWContenedorPestanyas id="Detalle"} {CWPestanya tipo="lis" panelAsociado="ediDetalle" estado=$estado_edi} {/CWContenedorPestanyas} {/if} {/CWMarcoPanel} {/CWVentana}
Una vez tenemos claro como definir los ficheros correspondientes a la pantalla, vamos a comentar un aspecto del mappings.php respecto a un maestro/detalle. Respecto al maestro, hay que añadir una entrada que permita recargar el detalle a partir del registro seleccionado en el maestro, para ello se deben agregar las siguientes líneas en el mappings.php para la clase del maestro:
$this->_AddMapping('TinvTipos__recargar', 'TinvTipos'); $this->_AddForward('TinvTipos__recargar', 'gvHidraSuccess', 'index.php?view=views/patronesMD/M(FIL-LIS)-D(LIS)/p_tiposubtipo.php&panel=listar'); $this->_AddForward('TinvTipos__recargar', 'gvHidraError', 'index.php?view=views/patronesMD/M(FIL-LIS)-D(LIS)/p_tiposubtipo.php&panel=listar');
En este caso nos encontramos con un maestro con más de un detalle, visualmente tendremos un panel superior que corresponderá con el maestro, y en la parte inferior tendremos los detalles, estos serán accesibles mediante unas solapas superiores (ver imagen en el capítulo X Características técnicas).
En general, la forma de funcionar es muy parecida al maestro-detalle explicado en el punto anterior, salvo pequeñas diferencias. Igual que siempre, tenemos que definir una clase por cada panel, es decir, una por el maestro y otra por cada detalle que vayamos a tener. En este caso, en el maestro tenemos que añadir la referencia a todos los detalles que se vayan a tener con el método addHijo().
class Expedientes extends gvHidraForm_DB { function Expedientes() { ... $this->addHijo('informes',array('ediNexpediente'),array('lisNexpediente')); $this->addHijo('deficiencias',array('ediNexpediente'),array('lisNexpediente')); ... } }
Los paneles detalle añadirán la referencia al padre igual que en el caso de un maestro-detalle simple, con el método addPadre().
En el fichero de views tendremos que definir todos los paneles detalle que tengamos y agregarlos con el método agregarPanelDependiente(). Otra peculiaridad de este panel es que tenemos que definir las solapas que irán asociadas a los paneles detalle, para ello tenemos que definir un array asociativo con tantos arrays como detalles, estos deben tener dos claves, "panelActivo" y "titDetalle", que se corresponden, respectivamente, con el nombre de la clase manejadora del detalle y el texto que queramos que aparezca en la solapa. Otro punto a tener en cuenta es indicar qué detalle queremos que aparezca activo, para ello tenemos que asignar a la variable smarty smty_panelActivo el nombre de la clase manejadora que queramos.
<?php //MAESTRO $comportamientoVentana= new IgepPantalla(); $panelMaestro = new IgepPanel('expedientes',"smty_datosTablaM"); $panelMaestro->activarModo("fil","estado_fil"); $panelMaestro->activarModo("edi","estado_edi"); $datosPanel = $comportamientoVentana->agregarPanel($panelMaestro); //DETALLE $panelDetalle = new IgepPanel('informes',"smty_datosInformes"); $panelDetalle->activarModo("lis","estado_lis"); $datosPanelDetalle = $comportamientoVentana->agregarPanelDependiente($panelDetalle,"expedientes"); $panelDetalle = new IgepPanel('deficiencias',"smty_datosDeficiencias"); $panelDetalle->activarModo("edi","estado_edi"); $datosPanelDetalle = $comportamientoVentana->agregarPanelDependiente($panelDetalle,"expedientes"); // Botones detalles // panelActivo: Nombre de la clase manejadora del detalle q vamos a activar // titDetalle: Título q aparecerá en la pestaña del panel $detalles = array ( array ( "panelActivo" =>"informes", "titDetalle" =>"Informes" ), array ( "panelActivo" =>"deficiencias", "titDetalle" =>"Deficiencias" ) ); $s->assign('smty_detalles',$detalles); $s->assign('smty_panelActivo','informes'); $s->display('MaestroNDetalles/p_expedientes.tpl'); ?>
En la tpl también hay que señalar algunas diferencias respecto a un maestro-detalle simple. La parte que corresponde al maestro es exactamente igual que la explicada para el maestro-detalle, las diferencias las encontramos en la parte que corresponde a los detalles. Vamos a verlo por puntos:
Vemos en la sección detalles se comprueba, mediante un if de smarty, si en el maestro hay datos. Si los hay pasamos a dibujar las solapas de los diferentes detalles con el plugin CWDetalles.
A continuación englobamos cada panel detalle dentro de un if condicional que comprueba si el panel es el activo por defecto.
1 {CWVentana tipoAviso=$smty_tipoAviso codAviso=$smty_codError descBreve=$smty_descBreve textoAviso=$smty_textoAviso onLoad=$smty_jsOnLoad} {CWBarra usuario=$smty_usuario codigo=$smty_codigo customTitle=$smty_customTitle} {CWMenuLayer name="$smty_nombre" cadenaMenu="$smty_cadenaMenu"} {/CWBarra} 5 {CWMarcoPanel conPestanyas="true"} <!-- *********************** PANEL MAESTRO ***********************--> <!--*********** PANEL fil ******************--> 10 {CWPanel id="fil" action="buscar" method="post" estado=$estado_fil claseManejadora="expedientes"} ... {/CWPanel} <!-- ****************** PANEL edi ***********************--> 15 {CWPanel id="edi" tipoComprobacion="envio" esMaestro="true" itemSeleccionado=$smty_filaSeleccionada action="operarBD" method="post" estado="$estado_edi" claseManejadora="expedientes" accion=$smty_operacionFichaexpedientes} ... {/CWPanel} <!-- ****************** PESTAÑAS ************************--> 20 {CWContenedorPestanyas id="Maestro"} {CWPestanya tipo="fil" panelAsociado="fil" estado=$estado_fil ocultar="Detalle"} {CWPestanya tipo="edi" panelAsociado="edi" estado=$estado_edi mostrar="Detalle"} {/CWContenedorPestanyas} 25 <!-- ****************** PANELES DETALLES ***********************--> </td></tr> {if count($smty_datosTablaM ) gt 0 } {CWDetalles claseManejadoraPadre="expedientes" detalles=$smty_detalles panelActivo=$smty_panelActivo} <tr><td> 30 <!-- ****************** Detalle 1: INFORMES ***********************--> {if $smty_panelActivo eq "informes"} {CWPanel id="lisDetalle" tipoComprobacion="envio" action="operarBD" method="post" detalleDe="edi" estado="on" claseManejadora="informes"} ... 35 {/CWPanel} {CWContenedorPestanyas id="Detalle"} {CWPestanya tipo="lis" panelAsociado="lisDetalle" estado="on"} {/CWContenedorPestanyas} {/if} 40 <!-- ****************** Detalle 2: DEFICIENCIAS ***********************--> {if $smty_panelActivo eq "deficiencias" } {CWPanel id="ediDetalle" tipoComprobacion="envio" action="operarBD" method="post" detalleDe="edi" estado="on" claseManejadora="deficiencias"} ... 45 {/CWPanel} {CWContenedorPestanyas id="Detalle"} {CWPestanya tipo="edi" panelAsociado="ediDetalle" estado="on"} {/CWContenedorPestanyas} {/if} 50 {/if} {/CWMarcoPanel} {/CWVentana}
Vamos a explicar ahora como desarrollar un mantenimiento tipo árbol, uno de los patrones más complejos. El aspecto visual del árbol es el siguiente:
La pantalla se divide claramente en dos zonas. La zona de la derecha se corresponde con lo que es el árbol en sí, y la de la izquierda corresponde con un panel común (tabular o registro). El usuario puede ir navegando por el árbol, expandiendo los nodos tal y como se haya especificado en el código, una vez llegado a la opción que nos interese en la parte derecha aparecerá un panel que visualizará los datos correspondientes al nodo seleccionado (p.e. en la imagen se puede ver que se muestra una factura del tercer trimestre para el año 1993, que es el nodo seleccionado).
Primero hay que tener claro como va a ser la estructura del árbol, para poder definir los nodos y hojas del árbol. Estás definiciones, básicamente, se hacen declarando los "tipos" de nodos y como se obtienen sus hijos, indicando qué nodos aparecerán en la raiz, y los que vayan a ser hojas no tendrán especificación de sus hijos. De esta forma obtenemos un árbol muy flexible, en el que no hay que preocuparse de los niveles que va a tener.
Para definir un nodo (o nodo raiz) tenemos que especificar como se obtienen sus hijos, esto se puede hacer de dos modos:
SELECT: Los hijos se obtienen a través de una consulta a base de datos.
LISTA: Los hijos son fijos, se establecen mediante un array de valores.
Con estos dos modos de definición de nodos podemos ir dando la estructura que queramos al árbol.
Como en el resto de pantallas, el programador tendrá que completar un fichero TPL, un fichero PHP de views y, al menos dos, ficheros PHP de actions. Vamos a ir explicando la estructura y como trabajar en cada uno de estos ficheros.
Lo primero que se debe crear es un fichero PHP donde se va a definir toda la estructura del árbol. Este fichero extenderá de la clase gvHidraTreePatern, esta clase nos proporcionará los métodos adecuados para crear el árbol.
El comienzo de la clase es igual que cuando trabajamos con cualquier otro tipo de panel, cargando la conexión, tablas con las que trabajar... Pasamos a crear el árbol en sí, para ello creamos un objeto de la clase IgepArbol a partir del que definiremos la estructura con los métodos:
addNodoRaiz($tipoNodo, $etiqueta, $tipoDespliegue, $datosDespliegue, $conexion)
Con este método crearemos el nodo raíz, hay que tener en cuenta que podemos tener más de un nodo raíz. Los parámetros que se necesitan para definirlo son:
$tipoNodo: Nombre con el que se identificará el nodo.
$etiqueta: Texto que aparecerá en pantalla este nodo. Importante no introducir retornos de carro.
$tipoDespliegue: Nos indica el modo de obtención de los nodos hijos, puede tomar dos valores "SELECT", nodos hijos vienen de BD, o "LISTA", nodos hijos fijados por un array.
$datosDespliegue: Dependiendo de lo dicho en $tipoDespliegue.
Si tenemos "SELECT": nos encontraremos un array en la que el primer parámetro se corresponderá con el identificador del primer nivel del árbol, y el segundo parámetro será la select que obtendrá los valores correspondientes a este primer nivel. En la select tenemos que definir el texto que aparecerá en el árbol y darle el alias "etiqueta".
$arbol->addNodoRaiz("ANYOS", "Años de Facturas", "SELECT", array( "ANYO", "select anyo||' ('||count (1)||')' as \"etiqueta\",anyo from tinv_entradas group by anyo") );
Si tenemos "LISTA": Tendremos un array asociativo en el que se irá dejando como índice la etiqueta de los nodos y como valor el tipo de hijo correspondiente.
$arbol->addNodoRaiz('DECADAS',
'Años',
'LISTA',
array(
'Década de los 70'=>'1970',
'Década de los 80'=>'1980',
'Década de los 90'=>'1990')
);
$conexion: Se puede indicar una conexión alternativa a la propia del panel para el despliegue de dicha raíz.
addNodoRama($tipo,$modoDespliegue,$despliegue,$dsnAlternativo = '')
La diferencia entre éste y el anterior es que no tiene el parámetro $etiqueta, ya que la etiqueta sale de $datosDespliegue del padre. Todos los nodos del árbol excepto los que estén en la raíz se definen con este método.
setNodoPanel($tipoNodo, $claseManejadora, $dependencia, $conexion)
Este método permite al programador indicar que cierto tipo de nodo tiene asociada una representación en un panel asociado al arbol. Los parámetros que se necesitan en este método son:
$tipoNodo: Indicamos el tipo de nodo que se va a representar, que debe coincidir con alguno de los definidos con el método addNodoRama().
$claseManejadora: Nombre de la clase manejadora que define ese panel.
$dependencia: Un array con los campos que debe coger de los nodos superiores para pasárselos al panel antes de realizar la búsqueda.
$conexion: Posibilidad de establecer una conexión alternativa para este panel en concreto.
A continuación vemos un ejemplo de como se crea la estructura de un árbol:
<?php class PruebaArbol extends gvHidraTreePattern { function PruebaArbol() { $conf = ConfigFramework::getConfig(); $g_dsn = $conf->getDSN('g_dsn'); $nombreTablas= array("tinv_entradas"); parent::__construct($g_dsn,$nombreTablas); $arbol = new IgepArbol(); $arbol->addNodoRaiz("ANYOS","Años de Facturas","SELECT",array("ANYO","select anyo||' ('||count (1)||')' as \"etiqueta\",anyo from tinv_entradas group by anyo")); $arbol->addNodoRama("ANYO","LISTA",array("Por DG" =>"DGS","Por Trimestre"=>"TRIMESTRES","Ver Todas"=>"TODAS")); $arbol->addNodoRama("DGS","SELECT",array("FACTURA-DG","SELECT anyo,cdg,cdg as \"etiqueta\" FROM TINV_ENTRADAS WHERE anyo = '%anyo%' group by anyo,cdg order by cdg",array("anyo"))); $arbol->addNodoRama("FACTURA-DG","SELECT",array("FACTURA","SELECT anyo||'-'||nfactura as \"etiqueta\",anyo,nfactura FROM TINV_ENTRADAS WHERE anyo = '%anyo%' and cdg ='%cdg%'",array("anyo","cdg"))); ... $arbol->setNodoPanel("ANYO","TinvFacturasArbol",array("anyo"),"Facturas de %anyo%"); $arbol->setNodoPanel("FACTURA-DG","TinvFacturasArbol",array("anyo","cdg"),"Facturas de %anyo% de la %cdg%"); ... $this->addArbol($arbol); ... } ?>
Además de este fichero que crea la estructura principal, se debe crear un fichero php en el directorio actions por cada nodo panel que hayamos definido. Estas clases ya son clases manejadoras de un panel convencional (p.ej. un tabular, registro...).
A continuación debemos crear un archivo php en el directorio views que controle la presentación. En él se definen las asignaciones de los datos a la plantilla (tpl). En este caso no es un comportamiento genérico por lo tanto hay que instanciar la clase IgepPanelArbol (línea 3) que define el comportamiento del árbol, al que se le pasan los mismos parámetros que una pantalla genérica, el primero será el nombre de la clase manejadora que corresponde a ese panel, y el segundo, smty_datosPanel, variable smarty que se habrá definido en la tpl correspondiente al árbol. Activaremos la pestaña, método activarModo. Finalizamos agregando el árbol al panel con agregarPanelArbol().
1 <?php $comportamientoVentana= new IgepPantalla(); $panel = new IgepPanelArbol('PruebaArbol',"smty_datosPanel"); $panel->activarModo("edi","estado_edi"); 5 $comportamientoVentana->agregarPanelArbol($panel); $s->display('p_pruebaArbol.tpl'); ?>
Este fichero debe contener por un lado el árbol, y por otra parte, tantos paneles como tipos de nodos representables existan en el panel, los indicados con el método setNodoPanel(). Es importante tener en cuenta que se ha de mostrar sólo el panel activo, y para ello utilizamos la clausula {if} de Smarty, en la variable $smty_panelVisible nos vendrá el panel que queremos activo, es decir, nos vendrá el identificador que le habremos dado cuando hemos definido los nodos.
A continuación mostramos la tpl utilizada para el ejemplo:
{CWVentana tipoAviso=$smty_tipoAviso codAviso=$smty_codError descBreve=$smty_descBreve textoAviso=$smty_textoAviso} {CWBarra usuario=$smty_usuario codigo=$smty_codigo} {CWMenuLayer name="$smty_nombre" cadenaMenu="$smty_cadenaMenu"} {/CWBarra} {CWMarcoPanel conPestanyas="true"} <!-- ****************** PANEL edi ***********************--> {CWArbol estado=$estado_edi arbol=$smty_objArbol} {if $smty_panelVisible == "ANYOS" || $smty_panelVisible == "FACTURA-DG"} {CWPanel id="edi" tipoComprobacion="envio" itemSeleccionado=$smty_filaSeleccionada action="operarTabla" method="post" estado="on" claseManejadora="TinvFacturasArbol" accion=$smty_operacionFichaTinvFacturasArbol} {CWBarraSupPanel titulo=$smty_tituloPanel} {CWBotonTooltip imagen="01" titulo="Insertar registro" funcion="insertar" actuaSobre="ficha"} {CWBotonTooltip imagen="02" titulo="Modificar registro" funcion="modificar" actuaSobre="ficha"} {CWBotonTooltip imagen="03" titulo="Eliminar registro" funcion="eliminar" actuaSobre="ficha"} {CWBotonTooltip imagen="04" titulo="Limpiar registro" funcion="limpiar" actuaSobre="edicion"} {/CWBarraSupPanel} {CWContenedor} {CWFichaEdicion id="FichaEdicion" datos=$smty_datosPanel numPagInsertar="1"} {CWFicha} {CWCampoTexto nombre="anyo" editable="true" size="4" value=$smty_anyoNuevo textoAsociado="Año"} {CWCampoTexto nombre="nfactura" editable="false" size="6" value ="0" textoAsociado="Número Factura"} <br /><br /> {CWLista nombre="procedencia" radio="true" editable="true" datos=$smty_datosPreInsertadosTinvFacturasArbol.procedencia textoAsociado="Procedencia"} <br /><br /> {CWCampoTexto nombre="cif" editable="true" size="13" maxlength="13" textoAsociado="Cif"} {CWCampoTexto nombre="orden" editable="true" size="2" maxlength="2" textoAsociado="Orden" actualizaA="nombre"} {CWCampoTexto nombre="nombre" editable="false" size="40"} {CWBotonTooltip imagen="13" titulo="Ventana de seleccion" funcion="abrirVS" actuaSobre="cif" claseManejadora="TinvFacturasArbol"} <br /><br /> {CWLista nombre="cdg" size="2" editable="true" datos=$smty_datosPreInsertadosTinvFacturasArbol.cdg textoAsociado="D.General"} {CWCampoTexto nombre="fadquisicion" editable="true" size="10" conCalendario="true" textoAsociado="Fecha Adq"} <br /><br /> {CWCampoTexto nombre="fcertificacion" editable="false" size="10" textoAsociado="Fecha Certif"} {CWCampoTexto nombre="codFactura" editable="true" size="13" maxlength="13" textoAsociado="Cod. Factura"} </br></br> {/CWFicha} {CWPaginador enlacesVisibles="3"} {/CWFichaEdicion} {/CWContenedor} {CWBarraInfPanel} {CWBoton imagen="41" texto="Guardar" class="boton" accion="guardar" vCamposComprobar=$smty_validacionesTinvFacturasArbol} {CWBoton imagen="42" texto=" Cancelar" class="boton" accion="guardar" action="IgepPruebaArbol__cancelarArbol"} {/CWBarraInfPanel} {/CWPanel} {else} {CWPanel id="edi" tipoComprobacion="envio" action="operarTabla" method="post" detalleDe="edi" estado=$estado_edi claseManejadora=""} {CWBarraSupPanel titulo=""} {/CWBarraSupPanel} {CWContenedor} {CWFichaEdicion id="FichaDetalle" datos=$smty_datosPanel numPagInsertar="0"} {CWFicha} </br></br></br></br> NO HAY DATOS </br></br></br></br> {/CWFicha} {/CWFichaEdicion} {/CWContenedor} {CWBarraInfPanel} {CWBoton imagen="42" texto=" Cancelar" class="boton" accion="guardar" action="IgepPruebaArbol__cancelarArbol"} {/CWBarraInfPanel} {/CWPanel} {/if} {/CWArbol} <!-- ****************** PESTAÑAS ************************--> {CWContenedorPestanyas} {CWPestanya tipo="edi" estado=$estado_edi} {/CWContenedorPestanyas} {/CWMarcoPanel} {/CWVentana}
A continuación se muestra un ejemplo en el que la definición de jerarquía está definida en un único campo (subconcepto) y en funcion de su longitud obtenemos el tipo de nodo. La jerarquía de nodos buscada es:
ANYOS ANYO CAP1 (longitud 1) CAP2 (longitud 2) CAP3 (longitud 3) CAP5 (longitud 5)
La forma de definir los nodos seria, partiendo de cada nodo raíz, ir definiendo como se obtienen los nodos hijos y así sucesivamente hasta tener definidos todos los nodos. Puesto que el nodo CAP5 no tiene hijos no necesitamos definir ese nodo.
... $arbol->addNodoRaiz('ANYOS', 'Años de Subconceptos', 'SELECT', array('ANYO',"select concat(concat(concat(anyo,' ('),count(1)),')') as \"etiqueta\", anyo from tcom_subconceptos_anyo group by anyo")); $arbol->addNodoRama('ANYO', 'SELECT', array('CAP1',"SELECT anyo, subconcepto, concat(concat(subconcepto,' '),descrip) as \"etiqueta\" FROM tcom_subconceptos_anyo WHERE anyo = %anyo% and length(subconcepto)=1 order by subconcepto", array("anyo"))); $arbol->addNodoRama('CAP1', 'SELECT', array('CAP2',"SELECT anyo, subconcepto, concat(concat(subconcepto,' '),descrip) as \"etiqueta\" FROM tcom_subconceptos_anyo WHERE anyo = %anyo% and substr(subconcepto,1,1)='%subconcepto%' and length(subconcepto)=2 order by anyo,subconcepto", array("anyo",'subconcepto'))); $arbol->addNodoRama('CAP2', 'SELECT', array('CAP3',"SELECT anyo, subconcepto, concat(concat(subconcepto,' '),descrip) as \"etiqueta\" FROM tcom_subconceptos_anyo WHERE anyo = %anyo% and substr(subconcepto,1,2)='%subconcepto%' and length(subconcepto)=3 order by anyo,subconcepto", array("anyo",'subconcepto'))); $arbol->addNodoRama('CAP3', 'SELECT', array('CAP5',"SELECT anyo, subconcepto, concat(concat(subconcepto,' '),descrip) as \"etiqueta\" FROM tcom_subconceptos_anyo WHERE anyo = %anyo% and substr(subconcepto,1,3)='%subconcepto%' and length(subconcepto)=5 order by anyo,subconcepto", array("anyo",'subconcepto'))); ...