Paradigma MVC

From Joomla! Documentation

Revision as of 09:00, 31 January 2022 by Ing Pulizzi (talk | contribs) (Created page with "e più recente")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Other languages:
Bahasa Indonesia • ‎English • ‎Kiswahili • ‎Nederlands • ‎català • ‎español • ‎français • ‎italiano • ‎日本語

Questa pagina descrive il paradigma MVC per la progettazione Software Model-View-Controller implementato in Joomla.

Quando Joomla viene avviato per elaborare una richiesta da un utente, come un GET per una determinata pagina o un POST contenente i dati del modulo, una delle prime cose che fa Joomla è analizzare l'URL per determinare quale componente sarà responsabile dell'elaborazione la richiesta e trasferire il controllo a quel componente.

Lo farà eseguendo il file PHP del componente nel punto di ingresso per quel componente. Quindi, se il componente si chiama com_esempio, Joomla verrà eseguito:

* sul sito front-end: components/com_esempio/esempio.php
* nell'amministratore di back-end: administrator/components/com_esempio/esempio.php

Se stai sviluppando un componente, potresti effettivamente inserire tutto il codice del tuo componente in quei 2 file "esempio.php". Tuttavia, un vantaggio di seguire il modello Joomla MVC è che puoi sfruttare appieno le classi MVC della libreria Joomla, che riduce notevolmente la quantità di codice che devi scrivere.

Panoramica Joomla MVC

Joomla MVC

Codice punto di ingresso

Il ruolo principale del file PHP del punto di ingresso (esempio.php per com_esempio) è determinare quale controller eseguire.  Lo fa in base al parametro task (descritto più dettagliatamente in seguito) che comporta:
* determinare quale classe Controller deve essere caricata
* determinare dove trovare il codice per quella classe
* ottenere un'istanza di quella classe
* chiamare il metodo appropriato di quella classe. 

Titolare

Il responsabile del trattamento è responsabile dell'analisi della richiesta dell'utente, della verifica che l'utente sia autorizzato a eseguire tale azione e determina come soddisfare la richiesta.  Quest'ultimo riguarderà:
* determinare quale modello (o modelli) sarà necessario per soddisfare la richiesta e creare un'istanza di quel modello 
* effettuare chiamate ai metodi del modello per effettuare gli aggiornamenti del database richiesti
* determinare quale visualizzazione deve essere utilizzata per presentare la pagina Web all'utente e creare un'istanza di tale visualizzazione, oppure,
* se invece l'utente dovesse ricevere un reindirizzamento a un altro URL, determinando quell'URL di reindirizzamento.

Vista

La vista specifica cosa dovrebbe apparire sulla pagina Web e raccoglie tutti i dati necessari per l'output della risposta HTTP. 

Dopo che il controller ha creato l'istanza della vista, chiama il metodo setModel() della vista e passa l'istanza del modello. In questo modo la vista sa quale modello utilizzare e chiama i metodi del modello per ottenere i dati necessari per tornare all'utente.

Disposizione

La vista non restituisce HTML ma lo delega al layout.  Il layout contiene codice PHP che viene eseguito nel contesto del metodo (di solito display()) della vista, il che significa che se la vista contiene i dati di risposta, ad esempio, in $this ->items quindi il layout può accedere agli stessi $this->items quando emette l'HTML.

Separare la vista e il layout in questo modo consente un altro livello di flessibilità, poiché puoi facilmente impostare una sostituzione del layout per generare i dati della vista utilizzando il tuo HTML preferito.

=== Model ===
Il modello incapsula i dati utilizzati dal componente.  Nella maggior parte dei casi questi dati proverranno da un database, il database Joomla o un database esterno, ma è anche possibile che il modello ottenga dati da altre fonti, ad esempio tramite un'API di servizi Web in esecuzione su un altro server.  Il modello è anche responsabile dell'aggiornamento del database, se del caso.  Lo scopo del modello è isolare il titolare del trattamento e visualizzare dal dettaglio come i dati vengono ottenuti o modificati. 

Se il componente visualizza un modulo definito in XML utilizzando l'approccio Joomla Form, il modello gestisce l'impostazione e la configurazione dell'istanza Form, pronta per il layout per l'output dei campi utilizzando $form->renderField( ) ecc.

Elaborazione successiva

L'output del componente (in particolare l'output HTML del layout) non viene emesso direttamente come risposta HTTP, ma viene catturato e memorizzato nel buffer da Joomla.  Una volta che il layout ha generato l'output, il componente restituisce il controllo al framework Joomla che quindi carica ed esegue il modello.  Il modello combina l'output del componente e tutti i moduli attivi nella pagina corrente, in modo che possa essere consegnato al browser come una singola pagina. 

Il parametro task della richiesta HTTP

Joomla utilizza il parametro HTTP Request task per determinare quale controller deve essere utilizzato. Il parametro task può essere inviato in un HTTP GET o in un HTTP POST – infatti, Joomla non fa davvero distinzione tra i parametri GET e POST – ma il parametro task è solo un normale parametro HTTP, niente di speciale.

Nei file PHP del punto di ingresso principale di Joomla vedrai quasi sempre qualcosa come:

 $ controller = JControllerLegacy::getInstance('esempio');
 $controller->execute(JFactory::getApplication()->input->get('task'));
con 'esempio' sostituito da 'Contatto', 'Contenuto', 'Moduli' ecc.

Il metodo getInstance() di JControllerLegacy (o BaseController, come è ora noto dopo Joomla 3.8) è dove avviene tutta la magia. Esso

* esamina il parametro task 
* in base a questo parametro decide quale classe di controller caricare e in quale file si aspetta di trovare quella classe
* crea un'istanza di questa classe controller (che viene restituita da questa funzione)
* reimposta il parametro task come metodo che dovrebbe essere chiamato.

La riga di codice successiva ($controller->execute(JFactory::getApplication()->input->get('task'));) quindi chiama il metodo execute() dell'istanza del controller con il parametro che ora è il metodo da eseguire, e il metodo execute esegue fondamentalmente il metodo passato.

Il parametro task è della forma xy, dove x rappresenta il tipo di controller e y il metodo da chiamare. Il tipo di controller potrebbe essere assente, nel qual caso viene eseguito il metodo in controller.php. Se il tipo di controller è presente, viene utilizzato uno dei controller nella cartella controllers. Se il parametro task non è impostato affatto, viene eseguito il metodo display() in controller.php. La tabella seguente elenca le possibilità per un componente chiamato com_esempio.

Form of task Controller file Controller class Controller method
controllerType.method controllers/controllerType.php ExampleControllerControllerType method
eg items.process controllers/items.php ExampleControllerItems process
method(no controllerType set) controller.php ExampleController method
(task not set) controller.php ExampleController display

Quanto sopra vale sia per il sito front-end che per l'amministratore back-end, tranne per il fatto che per l'amministratore tutto avviene nella cartella administrator.

Pubblica/Richiesta/Richiedi modello

Post-request-get1.jpg

Joomla segue il modello Post/Redirect/Get, il che significa che quando un utente invia un modulo in un HTTP POST, piuttosto che Joomla risponde al POST con una pagina HTML reindirizza a un'altra pagina a cui il browser accederà con un HTTP GET.

Questo è caratterizzato quando l'amministratore visualizza la pagina Contenuto/Articoli, come mostrato nel primo diagramma. L'azione da eseguire è indicata dal parametro task e sia essa che i relativi dati vengono inviati nella richiesta POST. Una volta eseguita l'azione, la pagina Web successiva da visualizzare viene definita nel reindirizzamento HTTP.

Post-request-get2.jpg

Il secondo diagramma illustra il modello quando un amministratore modifica un articolo. In questo caso c'è il passaggio aggiuntivo di visualizzare il modulo di modifica, che ancora una volta Joomla gestisce inviando un reindirizzamento HTTP in risposta alla richiesta originale di modificare un articolo. (Al punto 3 Joomla (in BaseDatabaseModel) memorizza un "ID di modifica" nella sessione e i controller dei componenti controllano questo ID al punto 4, per assicurarsi che gli utenti non possano semplicemente specificare l'URL del modulo direttamente, senza passare dal punto 3 ).

I numeri rossi nei cerchi verdi nel diagramma si riferiscono ai diversi tipi di richieste HTTP che Joomla sta gestendo, e vedremo nella prossima sezione che sono state definite diverse classi MVC di Joomla per soddisfare questi 5 casi.

Classi Joomla MVC

Ci sono diverse classi MVC della libreria Joomla in librerie/src/MVC e questa sezione mira a fornire una panoramica di queste classi e spiegare quando il tuo componente dovrebbe utilizzare ciascuna classe.  Non tenta di fornire una descrizione completa delle funzionalità di ciascuna classe.
=== Classi Base MVC ===
Le 3 classi base MVC sono BaseController (precedentemente chiamato JControllerLegacy), HtmlView (precedentemente chiamato JViewLegacy) e BaseDatabaseModel (precedentemente chiamato JModelLegacy).
La funzionalità all'interno di BaseController include:
* i metodi getInstance() ed execute() descritti sopra, che insieme trovano il controller del componente ed eseguono il metodo appropriato, il tutto basato sul valore del parametro task. 
* funzioni per trovare la classe di visualizzazione appropriata da utilizzare (basata sull'impostazione del parametro view all'interno della richiesta HTTP) e dove cercare il file PHP che dovrebbe contenere questa classe.
* eseguendo il file PHP della classe e creando un'istanza della vista
* utilizzando il metodo BaseDatabaseModel::getInstance() per ottenere un'istanza del modello associata alla vista utilizzata
* il metodo display() predefinito, che ottiene le istanze delle classi view e model (incluso fornendo all'istanza view un collegamento all'istanza del modello), e quindi chiama il metodo display() della classe view.
La classe HtmlView include:
* il metodo display(), che esegue il file di layout
* codice per trovare il file di layout, tenendo conto di una sostituzione del layout che potrebbe essere stata inserita nella struttura della cartella del modello
* codice per impostare l'istanza del modello e successivamente recuperarla
* un metodo get() generico che quando chiamato come get("qualcosa") lo converte in una chiamata sul modello $model->getSomething() .
Il BaseDatabaseModel contiene:
* il metodo statico getInstance() che trova il file PHP contenente il codice per il modello, lo esegue e restituisce un'istanza della classe del modello.
* codice per ottenere un'istanza della classe Table che gestirà l'interfaccia alla tabella del database sottostante per questo componente.
* codice di base per la creazione di uno "stato" del modello.  Questa funzionalità è utile se il componente e/o più moduli visualizzati nella pagina Web utilizzano tutti gli stessi dati di base.  In questo caso possono condividere la stessa istanza del modello e lo "stato" del modello agisce come un contenitore per condividere i valori degli elementi nel componente e nei moduli. 
In generale, l'utilizzo delle classi base è una buona opzione se il componente visualizza un singolo elemento su una pagina del sito.

Classi di visualizzazione di livello superiore

Sono disponibili 3 classi di visualizzazione di livello superiore, che ereditano tutte direttamente dalla classe base HtmlView.  Il nome della classe (e quindi il nome del file PHP) dà una buona indicazione del suo utilizzo:
* CategoryView – per visualizzare una categoria ei suoi figli
* CategoriesView – per visualizzare tutte le categorie a un certo livello nella gerarchia delle categorie e il numero di elementi associati a ciascuna categoria
* CategoryFeedView – per generare un feed. 
L'uso delle classi CategoryView o CategoriesView potrebbe essere utile se stai seguendo il paradigma di come com_content restituisce queste informazioni sul sito, ma per il resto probabilmente non è così utile. 

La classe CategoryFeedView ti aiuterà se stai fornendo un feed, come descritto in Adding a Feed.

Classi di controllori di livello superiore

Esistono 2 classi di controller di livello superiore, ognuna delle quali eredita da BaseController. 

AdminController contiene metodi che gestiscono i tipi di operazioni che possono essere eseguite su più elementi, ad es

* eliminare
* check-in 
* modifica dello stato di pubblicazione
* modifica dell'ordinamento relativo dei record
Tuttavia, tieni presente che non supporta le operazioni abilitate dal pulsante Batch ad esempio nella pagina Contenuto/Articoli. 
Il codice generalmente chiama il metodo del modello correlato per effettuare l'operazione, imposta il messaggio in base al successo dell'operazione del modello e imposta il reindirizzamento alla stessa pagina.  Per questo motivo è molto utile nel caso 2 mostrato nei diagrammi sopra in Post/Request/Get pattern. 

Il nome AdminController suggerisce che questo controller deve essere utilizzato solo sulla funzionalità dell'amministratore back-end, tuttavia non è così. È opportuno utilizzarlo anche sul front-end del sito.

FormController contiene metodi associati alla modifica di un singolo elemento

* gestione di una richiesta di modifica di un articolo – che implica la verifica che l'utente sia autorizzato a modificare l'articolo e che non sia già stato ritirato e se questi controlli vengono superati, l'articolo viene ritirato (se quel componente ha abilitato il checkout) e viene emesso un reindirizzamento per visualizzare il modulo di modifica
* gestione di una richiesta di aggiunta di un nuovo elemento, che implica la verifica che l'utente sia autorizzato a modificare l'elemento e si traduce in un reindirizzamento per visualizzare un modulo di modifica vuoto
* gestione del salvataggio di un elemento in fase di modifica o creato da nuovo: il codice verifica che l'utente sia autorizzato a eseguire l'operazione e chiama il metodo del modello appropriato per salvare l'elemento nuovo/modificato.
* gestire l'annullamento di una modifica, reindirizzando l'utente alla pagina appropriata (e archiviando il record se necessario).
* gestione delle operazioni avviate tramite il pulsante Batch
Il FormController è quindi adatto ai casi 3 e 5 mostrati nei diagrammi sopra in Post/Request/Get pattern.

Classi di modelli di livello superiore

Model hierarchy.jpg

Il diagramma mostra l'albero di ereditarietà dei modelli MVC della libreria Joomla.

ItemModel è quasi uguale a BaseDatabaseModel; ha solo un metodo extra getStoreId() che è rilevante quando hai un componente e/o più moduli che condividono lo stesso modello e vuoi distinguere tra set di dati rilevanti per ciascuno.

Oltre a getStoreId(), ListModel ha capacità relative all'ottenimento di una serie di record da visualizzare su una pagina web, incluso il supporto per l'impaginazione. Si noti che la capacità di impaginazione potrebbe essere ancora leggermente diversa tra il front-end e il back-end – vedere this issue. Il ListModel è utile per supportare il caso 1 nei diagrammi sopra.

FormModel include il supporto per i moduli Joomla, sia per impostare il modulo in modo che possa essere visualizzato, sia per convalidare i dati del modulo inviati nel POST. Inoltre, dispone di metodi per implementare il check-in e il check-out dei record del database. Quindi è adatto per gestire i casi 3 e 4 nei diagrammi sopra.

AdminModel estende FormModel, quindi ha tutte le capacità per la gestione dei moduli, ma ha anche metodi per la gestione degli aggiornamenti del database, inclusa la capacità di aggiungere, aggiornare ed eliminare record, nonché il supporto per la gestione delle operazioni in batch. Quindi è adatto per gestire i casi 2 e 5 nei diagrammi sopra. Come con AdminController, questo modello non è solo appropriato per la funzionalità dell'amministratore, ma può essere utilizzato anche sul front-end.

Tuttavia, sebbene FormModel e AdminModel supportino casi diversi nel flusso associati alla modifica di un record, in pratica è comune utilizzare lo stesso modello per tutti i diversi passaggi del flusso. Tutti i componenti principali di Joomla utilizzano lo stesso modello in questi passaggi, quindi estendono tutti AdminModel invece di FormModel.

Qualcosa da tenere presente se si utilizza lo stesso modello nel flusso di "modifica articolo" è che il codice del modello esegue 2 scopi:

# preparazione dei dati da mostrare su una pagina web
# preparazione di un modulo, da visualizzare su una pagina web o per la convalida dei dati POST
Quando si utilizza il modello perché si sta gestendo un POST (ovvero i casi 3 e 5 nel diagramma), ogni sforzo impiegato nella preparazione dei dati per una pagina Web sarà sprecato.  (Infatti, nella chiamata al metodo FormController getModel(), il parametro $config è impostato su array('ignore_request' => true) per impostazione predefinita, il che comporta che il metodo populateState del modello non venga eseguito, forse per risparmiare questo sforzo sprecato).

Come abbiamo visto Joomla:
* usa il parametro task per definire le azioni, che generalmente risultano in una sorta di aggiornamento del database e finiscono sempre con un reindirizzamento
* non imposta un parametro task quando deve essere visualizzata una pagina web
* ha funzionalità avanzate in controller di livello superiore e classi di modelli che possono semplificare notevolmente il codice (tutti possono essere utilizzati sia sul front-end che sul back-end).

La scelta di quali classi di controller e modelli estendere è più facile sul back-end, perché segui semplicemente lo schema dei componenti principali di Joomla.

Per il front-end ecco una guida approssimativa:

Semplicemente visualizzare un record o un set di record, senza fornire la possibilità di modificare nulla:

* il controller estende BaseController 
* model estende BaseDatabaseModel o (in particolare se stai condividendo un modello tra un componente e moduli) ItemModel se si tratta di un singolo record, ListModel se si tratta di più record. 

Visualizzazione di un modulo con più record (ma il modulo non è definito in un file XML), inclusa la possibilità di selezionare più record e applicarvi una sorta di operazione (ad es. eliminazione, pubblicazione):

* il controller estende BaseController 
* il modello estende ListModel, a meno che non si utilizzi lo stesso modello per visualizzare il modulo e gestire gli aggiornamenti, nel qual caso utilizzare AdminModel 

Gestire i POST HTTP da quel modulo nei sottocontroller:

* il controller estende AdminController 
* il modello estende AdminModel 

Visualizzare un modulo con un singolo record, in cui il modulo è definito in un file XML e consentire all'utente di modificarlo, oppure un record vuoto e consentire all'utente di creare un record:

* il controller estende BaseController 
* il modello estende FormModel, a meno che tu non stia utilizzando lo stesso modello per visualizzare il modulo e gestire gli aggiornamenti (come di solito accade), nel qual caso usa AdminModel 

Gestire i POST HTTP da quel modulo nei sottocontroller:

* il controller estende FormController 
* il modello estende AdminModel 

Vedi anche

Serie di sviluppo componenti

Sviluppo di un componente MVC per Joomla! 4.x

Sviluppo di un componente MVC per Joomla! 3.x