Design per la creazione di un menu basato sul tipo di utente

2

problema
Sto costruendo un'applicazione PHP che ha un menu principale, che a sua volta contiene varie "sezioni" o "sottotitoli" con vari collegamenti. Esistono diversi tipi di utente come SuperAdmin, Admin, Insegnante, Studente, ecc. E ogni tipo dovrebbe visualizzare una struttura di menu potenzialmente diversa. Sembra che il mio cliente vorrebbe aggiungere più tipi lungo la linea.

Attualmente ho un enorme blocco if / elseif / ... che controlla quale tipo di utente sei e crea un array con array per tutte le sezioni, contenente ancora più array per ogni link (questi array contengono l'url, la classe e didascalia dell'URL). Al momento è lungo circa 700 linee. Come puoi vedere, questo sta diventando piuttosto complesso e stancante per funzionare. Quindi quello che ho tentato di fare è usare alcuni schemi di progettazione (di cui la mia conoscenza non è così straordinaria).

Tentativi non riusciti
Innanzitutto ho tentato di creare alcune implementazioni Builder : una per il collegamento stesso, una per la "sezione" e infine una per il menu stesso. Quindi ho tentato di implementare un modello Strategia per verificare il tipo di utente corrente e aggiungere collegamenti alle sezioni e queste sezioni al menu. L'ultimo tentativo è stato serializzare questo oggetto del menu sul DB e leggerlo da lì (dato che alcuni tipi di utenti possono avere sezioni / collegamenti configurati dinamicamente)

La vera domanda
Non ho idea se la mia logica sia anche lontanamente corretta a questo proposito, perché ho creato e cancellato completamente tutto il mio codice circa 4 volte ora che diventa complesso comprendere solo ciò che deve andare dove. Quindi suppongo che la mia vera domanda sia questa: Se dovessi costruire questo tipo di implementazione per i menu (o qualsiasi cosa in cui più oggetti sono incorporati in un altro oggetto, e più oggetti di quel tipo sono incorporati in un altro oggetto), come ci andresti? Quali modelli sarebbero utili e come li strutturerebbe per lavorare insieme senza uccidere il tuo cervello?

Grazie!

    
posta iLikeBreakfast 06.03.2014 - 23:40
fonte

3 risposte

1

Sistema di menu dinamico e ricorsivo PHP

Quando creavo il menu dinamico nel mio precedente lavoro, per il nostro CMS, avevamo una classe che crea / stampa dinamicamente il menu in base all'oggetto menu.

Visualizza l'esempio di output del codice sottostante

Dato che sei un po 'nuovo, non suggerisco di creare alcun menu di overkill, ma cerca di mantenerlo il più semplice possibile.

Suggerisco di creare una classe per il menu, in cui si invia / memorizza l'array del menu. In questo modo puoi rendere altri oggetti sbloccare / bloccare diversi oggetti del menu, o anche inviare un sottomenu a quella classe di menu (a seconda di quanto sia complesso farlo).

Ciò consente di creare dinamicamente il menu mentre si scorre il codice di sistema e di stampare il menu al termine dell'esecuzione del codice. In questo modo puoi mettere gli elementi del menu in base all'utente in ciascuna sezione del codice, che gestisce quella parte.

Ad esempio, quando si esegue il sistema, creare una funzione / metodo che controlli l'accesso dell'utente e soluzioni semplici, disporre di array hard-coded con oggetti di menu per ogni accesso utente o, se si esegue l'hardcore, creare dinamicamente gli array di menu. Dipende da te.

<?php
// Let's create the child menu array for the "Home" menu structure
$home[] = array('TITLE' => 'Home 1',
                'URL' => '/home-1-url-here',
                'CSS_CLASS' => 'sub-menu',
                'CHILDREN' => $home1Child);

$home[] = array('TITLE' => 'Home 2',
                'URL' => '/home-2-url-here',
                'CSS_CLASS' => 'sub-menu');

// Now we create the whole home array, with the children
$homeMenu = array('CSS_CLASS' => 'top-css-class',
                 'TITLE' => 'Home',
                 // If the top menu item is just a link, specify an URL
                 'URL' => '', 
                 // Or if it has children pass them on
                 'CHILDREN' => $home);

// Let's create the child menu array for the "Gallery" menu structure
$gallery[] = array('TITLE' => 'Gallery 1',
                'URL' => '/gallery-1-url-here',
                'CSS_CLASS' => 'sub-menu');

$gallery2Child[] = array('TITLE' => 'Gallery 2.1',
                'URL' => '/gallery-2.1-url-here',
                'CSS_CLASS' => 'sub-menu-child');
$gallery2Child[] = array('TITLE' => 'Gallery 2.2',
                'URL' => '/gallery-2.2-url-here',
                'CSS_CLASS' => 'sub-menu-child');

$gallery[] = array('TITLE' => 'Gallery 2',
                'URL' => '/gallery-2-url-here',
                'CSS_CLASS' => 'sub-menu',
                'CHILDREN' => $gallery2Child);

// Now we create the whole gallery array, with the children
$galleryMenu = array('CSS_CLASS' => 'top-css-class',
                 'TITLE' => 'Gallery',
                 // If the top menu item is just a link, specify an URL
                 'URL' => '', 
                 // Or if it has children pass them on
                 'CHILDREN' => $gallery);

$menu = new menu;
// Store the menu items we want in the menu
$menu->storeItem($homeMenu);
$menu->storeItem($galleryMenu);
// Print the menu
echo $menu->buildMenu();

Se vuoi anche creare sottomenu, fai in modo che la classe del menu funzioni in modo ricorsivo.

class menu {
   private $mainMenuClass = 'main-menu-class';
   private $parentClass = 'parent-menu-class';
   private $menu;

   public function storeItem($menuItem, $parentClass = '') { // If no $parentClass is specified, pick the default one
      // This stores the menu in an array
      $this->menu[] = $menuItem;
   }

   public function buildMenu() {
      // Let's break down the menu array, and start building it
      $html = '<ul class="'. $this->mainMenuClass .'">'. PHP_EOL;
      foreach($this->menu as $parentClass => $item) {
         $html .= '<li class="'. $item['CSS_CLASS'] .'"><a href="'. $item['URL'] .'">'. $item['TITLE'] .'</a>'. PHP_EOL;
         // Check if it's a recursive sub-menu (with children)
         // Now we send the children array to the buildChildrenItems() method
         $html .= $this->buildChildrenItems($item['CHILDREN']);
         $html .= '</li>'. PHP_EOL;
      }
      $html .= '</ul>'. PHP_EOL;
   return $html;
   }

   public function buildChildrenItems($menuSection) {
      // Put the recursive logics here so we can keep looping
      $html = '<ul class="'. $this->parentClass .'">'. PHP_EOL;
      foreach($menuSection as $item) {
          $html .= '<li class="'. $item['CSS_CLASS'] .'"><a href="'. $item['URL'] .'">'. $item['TITLE'] .'</a>'. PHP_EOL;
          // Now here is where the recursive magic happends
          // If the child item has even more children, call this method once again for those children
          $html .= ( isset($item['CHILDREN']) && is_array($item['CHILDREN']) ) ? $this->buildChildrenItems($item['CHILDREN']) : ''; 
          $html .= '</li>'. PHP_EOL;
      }
      $html .= '</ul>'. PHP_EOL;
   return $html;
   }
}

>?

Da qui puoi semplicemente progettare il menu come vuoi, usando le classi CSS.

Se vuoi renderlo ricorsivo (con sottomenu dinamici), allora fai semplicemente le logiche ricorsive prima di chiamare il metodo buildChildrenItems (). Questo è incluso nell'esempio di codice sopra.

Per i menu ricorsivi più complessi, prova questi array.

$home1Child[] = array('TITLE' => 'Home 1.1',
                'URL' => '/home-1.1-url-here',
                'CSS_CLASS' => 'sub-menu-child');

$home121Child[] = array('TITLE' => 'Home 1.2.1',
                    'URL' => '/home-1.2.1-url-here',
                    'CSS_CLASS' => 'sub-menu-child');

    $home121Child[] = array('TITLE' => 'Home 1.2.2',
                    'URL' => '/home-1.2.2-url-here',
                    'CSS_CLASS' => 'sub-menu-child');

$home1Child[] = array('TITLE' => 'Home 1.2',
                'URL' => '/home-1.2-url-here',
                'CSS_CLASS' => 'sub-menu-child',
                'CHILDREN' => $home121Child);

$home1Child[] = array('TITLE' => 'Home 1.3',
                'URL' => '/home-1.3-url-here',
                'CSS_CLASS' => 'sub-menu-child');

$home[] = array('TITLE' => 'Home 1',
                'URL' => '/home-1-url-here',
                'CSS_CLASS' => 'sub-menu',
                'CHILDREN' => $home1Child);

$home[] = array('TITLE' => 'Home 2',
                'URL' => '/home-2-url-here',
                'CSS_CLASS' => 'sub-menu');

$home[] = array('TITLE' => 'Home 3',
                'URL' => '/home-3-url-here',
                'CSS_CLASS' => 'sub-menu');

// Now we create the whole home array, with the children

$homeMenu = array('CSS_CLASS' => 'top-css-class',
                 'TITLE' => 'Home',
                 // If the top menu item is just a link, specify an URL
                 'URL' => '', 
                 // Or if it has children pass them on
                 'CHILDREN' => $home);

// Let's create the child menu array for the "Gallery" menu structure
$gallery[] = array('TITLE' => 'Gallery 1',
                'URL' => '/gallery-1-url-here',
                'CSS_CLASS' => 'sub-menu');

$gallery2Child[] = array('TITLE' => 'Gallery 2.1',
                'URL' => '/gallery-2.1-url-here',
                'CSS_CLASS' => 'sub-menu-child');
$gallery2Child[] = array('TITLE' => 'Gallery 2.2',
                'URL' => '/gallery-2.2-url-here',
                'CSS_CLASS' => 'sub-menu-child');

$gallery[] = array('TITLE' => 'Gallery 2',
                'URL' => '/gallery-2-url-here',
                'CSS_CLASS' => 'sub-menu',
                'CHILDREN' => $gallery2Child);

// Now we create the whole gallery array, with the children
$galleryMenu = array('CSS_CLASS' => 'top-css-class',
                 'TITLE' => 'Gallery',
                 // If the top menu item is just a link, specify an URL
                 'URL' => '', 
                 // Or if it has children pass them on
                 'CHILDREN' => $gallery);

Visualizza l'esempio di output del codice sopra

Infine, nelle diverse classi, ad esempio, diciamo la Galleria. Crea l'array del menu della galleria, controlla il tipo di accesso che l'utente ha e costruiscilo correttamente. Quindi invii l'array del menu della galleria alla classe del menu, come mostrato sopra.

Questo concetto è utile anche per le espansioni future, quindi quando aggiungi una nuova classe / sezione sul sito web, diciamo un libro degli ospiti. Tutte le logiche del menu sono costruite in quella classe e appena inviate alla classe del menu dinamico che la costruisce.

Non consiglio di inserire tutte le logiche del menu in un unico grande file di menu, ma mentre esegui il codice di sistema, elabora ogni sezione e costruisci l'oggetto del menu mentre procedi.

Spero che questo ti aiuti sulla strada!

PS. Se si dispone di un sacco di tipi di accesso utente e si desidera mantenere un codice pulito, inserire gli array di menu per ogni accesso utente in file php separati. (user_type_member.php o user_type_admin.php).

Nel codice php, dove sono scritti gli array, basta fare un controllo del tipo di utente e chiamare il file php corrispondente per caricare l'array per quell'utente.

switch($userType) {
   default: 
   case 'visitor': include('user_type_visitor.php'); break;
   case 'member': include('user_type_member.php'); break;
   case 'admin': include('user_type_admin.php'); break;
}

Saluti, Andreas.

    
risposta data 12.03.2014 - 12:42
fonte
0

Suggerirei di scrivere un MenuFactory che prende un elenco di utenti / ruoli / permessi che a sua volta richiama tutti i builder richiesti per creare la struttura del menu attuale. In questo modo la costruzione del menu è incapsulata e l'interfaccia attraverso la factory dovrebbe essere abbastanza flessibile da gestire l'aggiunta o la rimozione di utenti / ruoli in futuro.

    
risposta data 12.03.2014 - 15:25
fonte
-1

Sembra che tu abbia pochi tipi di utenti. Perché non crei una gerarchia di classi di menu, quindi in cima c'è un AbstractMenu e in fondo sono StudentMenu , TeacherMenu ecc.? Vedi anche la risposta accettata per questa revisione del codice , che suggerisce di utilizzare un'interfaccia invece di una classe astratta.

Oltre a ciò puoi prendere in considerazione la creazione di Menu e MenuFactory classi in modo che tu possa ad esempio chiamare MenuFactory->getStudentMenu() e ottenere un'istanza concreta di Menu che si adatti a un Student utente. Quindi i dettagli sulla creazione di menu specifici del tipo utente saranno encapsulated in metodi separati.

Puoi anche combinare questi approcci e avere informazioni statiche popolate nel costruttore di classi e le informazioni dinamiche aggiunte da una fabbrica.

    
risposta data 11.03.2014 - 15:12
fonte

Leggi altre domande sui tag