En el foro de Xlinesoft, un desarrollador explica con buen criterio, es mi impresión, que ver la información de «Maestro» y «Detalle», en una página «LIST», más cuando son 3 o 4 niveles de «detalle» de información es muy complejo para el usuario del aplicativo y que si había alguna otra posibilidad de tener esa capacidad de detalles y fuese más claro para los usuarios.
Por mi experiencia, me he encontrado desarrollando sistemas en donde un ítem, cómo expediente o contrato, tiene múltiples informaciones dependientes de esta entidad principal y que en los sistemas en donde los usuarios entienden bien estas relaciones es viendo esta información como un «árbol jerárquico» donde se van abriendo «hojas» por tipo de entidad y registros de ese tipo, dependientes de la información principal.
Objetivo
Representar información jerárquica relacionada a través de un «árbol», en este caso, vamos a utilizar un menú secundario para presentar la información jerárquica.
DEMO: https://fhumanes.com/menu_dinamico/
Solución Técnica
Tenemos esta representación:
Y el ejemplo produce este menú y organización de la información, cuando se pulsa el botón verde con título «tree»:
En el menú se crea enlaces de:
- El registro «Maestro» donde se cliqueo el botón verde.
- Todos los registros dependientes del «Maestro» de la entidad «Detalle».
- Debajo de los registros «Detalle» se muestran los registros de la entidad «Detalle2».
En el ejemplo los enlaces se hacen a las páginas «VIEW», pero se puede hacer a cualquier tipo de página. El menú secundario se crea todo él dinámicamente.
El utilizar el elemento menú ha sido por:
- Representa la jerarquía de la información.
- En PHPRunner, tiene en cuenta la seguridad y sólo mostrará la opción si el usuario, tiene acceso al registro en la acción que esté configurado.
Desde mi punta de vista, PHPRunner tiene desarrollado muy poco este tema y faltan métodos para añadir atributos del menú, como son los iconos y otros. También, se pierde el foco de la opción del menú cuando pasamos de página «View» a página «Edit», pues marca el primer elemento del menú que tiene la misma entidad (tabla o vista) que estamos editando.
Aunque la solución no satisface todos los objetivos que me había marcado, creo que un buen ejemplo para la creación de los menú dinámicos y por ello, lo estoy publicando.
Consideraciones que he tenido en cuenta:
- La construcción del menú se ejecuta antes de cualquier evento de la tabla que estemos tratando, por ello, la estructura debe estar creada antes.
- En cada opción, que se ejecute del menú, se vuelve a crear el menú, por ello lo que he hecho es definir un array con las opciones del menú y en el evento «Modify Menu» pasa la información de ese array a la definición del menú. Con esto hacemos mucho más rápido la creación del menú.
Desde la parte de ejecución «server» del botón «verde» de 3 estados se ejecuta este fichero que crear el array descrito «menu_array.php»:
<?php
$id = $_SESSION['id_maestro'];
$menu_arr = array();
$count = 1;
// Type = E/T/G (Externo/Tabla/Grupo
$menu_arr[] = array('id'=>$count,'type'=>'E','name'=>'Menú principal','url'=>'menu_maestro_list.php','parent'=>'0');
/*
$count += 1;
$count_parent = $count;
$menu_arr[] = array('id'=>$count,'type'=>'G','name'=>'Información','parent'=>'0');
*/
$rs = DB::Query("select * from menu_maestro WHERE id_menu_maestro = $id");
$data = $rs->fetchAssoc();
$count += 1;
$name= 'Código: '.$data['codigo'];
$params="editid1=$id&v_parent=$id";
$menu_arr[] = array('id'=>$count,'type'=>'T','name'=>$name,'table'=>'v_maestro','page'=> 'view','params'=>$params,'parent'=>0);
$count += 1;
$count_parent = $count;
$menu_arr[] = array('id'=>$count,'type'=>'G','name'=>'Detalles','parent'=>'0');
$rs = DB::Query("select * from menu_detalle WHERE menu_maestro_id = $id ORDER BY codigo");
while( $data = $rs->fetchAssoc() )
{
$count += 1;
$name= 'Código: '.$data['codigo'];
$params="editid1=".$data['id_menu_detalle']."&v_parent=$id";
$menu_arr[] = array('id'=>$count,'type'=>'T','name'=>$name,'table'=>'v_detalle','page'=> 'view','params'=>$params,'parent'=>$count_parent);
// Siguiente nivel de Detalle2
$count += 1;
$count_parent2 = $count;
$menu_arr[] = array('id'=>$count,'type'=>'G','name'=>'Detalles2','parent'=>$count_parent);
$rs2 = DB::Query("select * from menu_detalle2 WHERE menu_detalle_id =".$data['id_menu_detalle']." ORDER BY codigo");
while( $data2 = $rs2->fetchAssoc() )
{
$count += 1;
$name= 'Código: '.$data2['codigo'];
$params="editid1=".$data2['id_menu_detalle2']."&v_parent=".$data['id_menu_detalle'];
$menu_arr[] = array('id'=>$count,'type'=>'T','name'=>$name,'table'=>'v_detalle2','page'=> 'view','params'=>$params,'parent'=>$count_parent2);
}
}
custom_error(30,"Array Menú: ".print_r($menu_arr,true)); // To debug
$_SESSION['menu_especial'] = $menu_arr;
Y desde el evento de «Modify Menu» se ejecuta el fichero «build_menu.php»:
<?php
$menu_arr = $_SESSION['menu_especial'];
$items_arr = array();
foreach ($menu_arr as &$row) {
switch ($row['type']) {
case 'E': // Externo
$name = $row['name'];
$url = $row['url'];
$parent = $row['parent'];
if ($parent > 0) {
$parent = $items_arr[$parent]->id ; // Conversión de referencias
}
$item = $menu->addURL( $name, $url, $parent );
$items_arr[$row['id']] = $item; // para conversión referencias
break;
case 'G': // Grupo
$name = $row['name'];
$parent = $row['parent'];
if ($parent > 0) {
$parent = $items_arr[$parent]->id ; // Conversión de referencias
}
$item = $menu->addGroup( $name, $parent );
$items_arr[$row['id']] = $item; // para conversión referencias
break;
case 'T': // Tabla
$name = $row['name'];
$table = $row['table'];
$page = $row['page'];
$params = $row['params'];
$parent = $row['parent'];
if ($parent > 0) {
$parent = $items_arr[$parent]->id ; // Conversión de referencias
}
$item = $menu->addPageLink( $name, $table, $page, $parent);
$item->setParams($params);
$items_arr[$row['id']] = $item; // para conversión referencias
break;
}
}
También he ajustado la fuente del menú con esta definición en «custom css»:
.r-left:not(.r-left-collapsed) .r-menu [data-menu-top], .r-left:not(.r-left-collapsed) .r-menu [data-menu-inline] {
font-size: 12px;
}
@media print, (min-width: 768px) {
.r-vbar-page .r-left:not(.r-left-collapsed) .nav > li > a {
padding: 3px 10px;
}
}
Como siempre, para cualquier duda me podéis consultar a través de mi email [email protected].
Os facilito el proyecto para que podáis instalarlo en vuestro PC y podáis hacer todas las pruebas que requiráis.