Guía 74 – Crear menús dinámicamente

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.

DEMOhttps://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.

 

Adjuntos

Archivo Tamaño de archivo Descargas
zip PHPRunner 10.91 + backup de base de datos 64 KB 217

Blog personal para facilitar soporte gratuito a usuarios de PHPRunner