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.