In MVC, è possibile / dovrebbe essere eseguito il recupero dei dati di base dal modello nella vista?


10

Dato il concetto di "controller skinny, modelli fat" e l'accettazione generale che Views può richiamare direttamente i modelli quando richiedono dati per l'output, si dovrebbe considerare la gestione delle parti "get e display" delle richieste all'interno di Views e non del controller? Ad esempio (tentato di mantenere il codice abbastanza generico):

controllore

<?php

class Invoice extends Base_Controller {

    /**
     * Get all the invoices for this month
     */

    public function current_month() {

        // as there's no user input let's keep the controller very skinny,
        // DON'T get data from the Model here, just load the view

        $this->load->view('invoice/current_month');

    }

}

Visualizza

<?php

// directly retrieve current month invoices here

$invoices = $this->invoice_model->get_current_month();

// get some other display-only data, e.g. a list of users for a separate list somewhere on the page

$users = $this->user_model->get_users();

?>

<h1>This month's invoices</h1>

<ul>
<?php foreach ($invoices as $invoice) { ?>

<li><?php echo $invoice['ref']; ?></li>

<?php } ?>
</ul>

Per me, questo ha almeno un certo senso nei casi in cui una richiesta è essenzialmente solo una vista. Perché il Titolare dovrebbe raccogliere e trasmettere i dati alla Vista quando può recuperarli da solo? Ciò lascia il Controller aperto per l'elaborazione a "livello di applicazione" (ad es. Gestione delle richieste GET / POST, gestione dei diritti di accesso e autorizzazioni, ecc.), Nonché della riutilizzabilità dei Modelli e di tutte le altre cose utili.

Se questo esempio fosse esteso per consentire a un utente di filtrare i risultati, il controller gestirà semplicemente il POST dal modulo e passerà i filtri alla vista, che quindi richiederebbe nuovamente i dati, questa volta con i filtri.

È un approccio valido allo sviluppo di un'applicazione MVC? O sto trascurando una parte importante del ruolo che un controller dovrebbe svolgere?

Risposte:


17

Sì, tecnicamente si può fare. No, non dovrebbe essere fatto. E sì, ti stai perdendo un po 'di ciò per cui il controller è lì.

Il controller è lì per disaccoppiare la vista dal modello. Il disaccoppiamento è utile perché dovresti guardare il View come un codice quasi da buttare via. Man mano che la tecnologia dell'interfaccia utente cambia, si desidera ridurre al minimo le rilavorazioni necessarie per generare una nuova vista. Il controller abilita tale disaccoppiamento e fornisce un posto per il tuo codice che vivrà attraverso le tecnologie dell'interfaccia utente.

Funziona anche al contrario se è necessario aggiungere o modificare il modello. Tutte le modifiche a monte saranno contenute all'interno del Controller e le tue Viste saranno lasciate sole.

L'altro rischio è che mentre la vista è molto semplice ora , hai meno garanzie che rimarrà così semplice per tutta la sua vita. Chiamando il modello direttamente dalla vista (molto semplice), hai aperto un po 'la porta per consentire alle cattive pratiche aggiuntive di insinuarsi in seguito quando la vista molto semplice deve diventare non molto semplice. Un futuro sviluppatore sarà tentato di effettuare più chiamate di modello dalla vista non molto semplice invece di refactoring del codice e di interagire con un controller.


1
Ottima risposta, grazie. Ampliare leggermente il tuo scenario "guardare avanti"; se in una pagina sono presenti informazioni comuni separate da quelle richieste (ad es. l'utente sta visualizzando un prodotto specifico, a lato viene mostrato un elenco generale di "ultime offerte speciali") come / dove deve offers_model->get_latest()essere effettuata la chiamata ? L'aggiunta di questo in ogni metodo nel controller (come ho tentato follemente in precedenza) sembra eccessivo e chiaramente non-DRY.
Adam Westbrook,

2
@AdamWestbrook Dai un'occhiata a MVVM. La parte di ViewModel che può risolvere questo problema specifico. È possibile aggiungere il offers_model->get_latest()a una ProductViewModelclasse base o qualcosa di simile.
Zachary Yates,

1
Fantastico, esaminerò sicuramente MVVM, grazie ancora.
Adam Westbrook,

Ottima risposta, manterrà provocatoriamente questo protagonista. Personalmente sono anche un grande fan di MVVM :)
Benjamin Gruenbaum il

@BenjaminGruenbaum Stai utilizzando MVVM in PHP? Se è così stai usando un particolare framework per questo?
Adam Westbrook,

6

Dato il concetto di "controller skinny, modelli fat" e l'accettazione generale che Views può chiamare direttamente i modelli quando si richiedono dati per l'output

No. Questo non è corretto. La vista non può chiamare direttamente i modelli. Le viste non dovrebbero avere accesso agli oggetti Modello, a meno che per qualche motivo il programmatore non abbia esposto tali oggetti alla Vista.

si dovrebbe considerare la gestione delle parti "get and display" delle richieste all'interno delle viste e non del controller?

Ciò sostanzialmente cancella il controller e sconfigge il punto di averli.

Perché il Titolare dovrebbe raccogliere e trasmettere i dati alla Vista quando può recuperarli da solo?

Il Titolare non raccoglie i dati. Il modello effettua la raccolta dei dati. Il Titolare decide se questi dati devono essere passati alla vista. La vista esegue solo la presentazione dei dati.

Se questo esempio fosse esteso per consentire a un utente di filtrare i risultati, il controller gestirà semplicemente il POST dal modulo e passerà i filtri alla vista, che quindi richiederebbe nuovamente i dati, questa volta con i filtri.

No.

Il controller verifica se i dati POST sono validi, quindi passa questi dati come opzioni al modello, che quindi interroga l'origine dati e restituisce i dati e il controller li passa alla vista.

È un approccio valido allo sviluppo di un'applicazione MVC? O sto trascurando una parte importante del ruolo che un controller dovrebbe svolgere?

Il controller funziona come un gestore per le richieste del browser. Un dispatcher invia la richiesta all'azione di un controller, che a sua volta distribuisce la richiesta ai Modelli. I modelli contengono tutta la logica aziendale (questa è la parte più grossa) e restituiscono i dati al controller. Il controller può quindi semplificare e regolare i dati in modo che sia più facile per la visualizzazione presentarli.

Il punto di vista è disaccoppiare la struttura e la dipendenza tra la presentazione di HTML e DataSource. Mentre questo può essere difficile. Le viste non presentano sempre dati provenienti direttamente da un modello. Il controller spesso aggiunge ulteriori dati rilevanti.

Sono sicuro che ci sono molti tutorial là fuori su MVC. Consiglierei di leggerne alcuni.


Grazie Mathew. Per chiarimenti, fino ad ora ho sempre disaccoppiato la vista e il modello con il controller come letto e suggerito. Tuttavia, da quando ho iniziato a leggere su come mantenere i controller "magri", mi sono solo chiesto cosa dovrebbe / potrebbe essere rimosso da loro, sembra che il processo di pensiero che mi ha portato a questa domanda sia stato un passo o due troppo lontano!
Adam Westbrook,

Quando inizi a ottenere modelli utilizzati da molti controller. La necessità che siano grassi diventa molto chiara. Quando la vista inizia a contenere molto PHP, sai che il tuo controller è troppo sottile. Quando i controller sono molto grassi. È difficile far funzionare altri controller allo stesso modo (ad esempio aggiungendo un servizio API).
Reactgular

3

Ho trovato la tua domanda molto interessante perché ho riscontrato lo stesso problema durante l'apprendimento di Python di recente.

Mentre le risposte fornite sono un argomento convincente, ho pensato di aggiungere un'altra opinione in cui mi sono imbattuto in cui il View ottiene lo stato del Modello senza passare attraverso il Controller.

MVC

È importante notare che sia la vista che il controller dipendono dal modello. Tuttavia, il modello non dipende né dalla vista né dal controller. Questo è uno dei principali vantaggi della separazione. Questa separazione consente di creare e testare il modello indipendentemente dalla presentazione visiva. La separazione tra view e controller è secondaria in molte applicazioni rich-client e, di fatto, molti framework di interfaccia utente implementano i ruoli come un unico oggetto. Nelle applicazioni Web, d'altra parte, la separazione tra view (il browser) e controller (i componenti lato server che gestiscono la richiesta HTTP) è molto ben definita.

Model-View-Controller è un modello di progettazione fondamentale per la separazione della logica dell'interfaccia utente dalla logica aziendale. Sfortunatamente, la popolarità del modello ha portato a numerose descrizioni errate. In particolare, il termine "controller" è stato usato per indicare cose diverse in contesti diversi. Fortunatamente, l'avvento delle applicazioni Web ha contribuito a risolvere alcune delle ambiguità perché la separazione tra la vista e il controller è così evidente.

Nella programmazione delle applicazioni in Smalltalk-80: come utilizzare Model-View-Controller (MVC) [Burbeck92], Steve Burbeck descrive due varianti di MVC: un modello passivo e un modello attivo.

Il modello passivo viene impiegato quando un controller manipola esclusivamente il modello. Il controller modifica il modello e quindi informa la vista che il modello è stato modificato e deve essere aggiornato (vedere la Figura 2). Il modello in questo scenario è completamente indipendente dalla vista e dal controller, il che significa che non c'è modo per il modello di segnalare i cambiamenti nel suo stato. Il protocollo HTTP ne è un esempio. Non esiste un modo semplice nel browser per ottenere aggiornamenti asincroni dal server. Il browser visualizza la vista e risponde all'input dell'utente, ma non rileva le modifiche ai dati sul server. Solo quando l'utente richiede esplicitamente un aggiornamento, il server viene interrogato per le modifiche.

MVC - Modello passivo

Non sono in grado di dire quale delle opinioni sia "giusta", e ad essere sincero, sono un po 'più confuso dopo aver letto le risposte qui e l'articolo collegato.

Testo completo dell'articolo qui .


Giusto, e l'altra cosa che aggiunge confusione è il client-server, che il MVC SmallTalk originale non ha davvero tenuto conto. Nel client-server (ad esempio con javascript) ci sono modelli, viste e controller orientati alla presentazione sul client e viste e controller orientati al dominio sul server, sebbene il server esegua anche un'elaborazione orientata alla presentazione che aggiunge confusione. Inoltre, a volte vogliamo che le viste di un dominio abbiano una certa persistenza, il che significa che i parametri della vista formano il proprio modello, che non fa necessariamente parte del modello di dominio.
Erik Eidt,

Grazie per il link, sapevo che non ero arrabbiato nel pensare questo! Questo è essenzialmente ciò che stavo andando fuori prima di aver portato l'idea un po 'troppo lontano, a condizione che il Modello non dipenda da nulla, che importanza ha come / dove si accede? Non ho ancora deciso quale approccio avrò per il mio prossimo sviluppo, ma questo sicuramente aiuta.
Adam Westbrook,

1

Un'altra cosa da considerare è che sembra che tu abbia caricato automaticamente il user_modele invoice_modelper consentire alla vista di accedervi. Affinché funzioni in modo affidabile, probabilmente caricerai automaticamente tutti i tuoi modelli (perché $this->load->model()in una vista sembra solo sbagliato, non è vero ...)

In questo modo si gonfia inutilmente il tuo stack caricando un sacco di cose che potrebbero non essere mai utilizzate. Parte del motivo per avere più modelli è consentire l'incapsulamento della logica correlata e caricare solo ciò che è necessario per una determinata attività.

Sembra CodeIgniter. Ho fatto molto sviluppo di elementi della configurazione e posso condividere, per esperienza personale, che non si desidera caricare automaticamente più di quanto sia necessario. Prova ad aggiungere $this->output->enable_profiler(TRUE);nel costruttore di un controller e giocherellare con i caricamenti automatici (inclusi helper come database): probabilmente vedrai un cambiamento significativo nei tempi di caricamento e di esecuzione, ma soprattutto nell'allocazione della memoria.


1
Aspetti positivi, hai ragione, questo si basa su CI, anche se ho rimosso parte della sintassi specifica per chiarezza. Ho preso l'abitudine di "caricare automaticamente" praticamente tutto per gran parte del tempo e per motivi DRY, mi è sembrato un po 'pazzo di avere load->modelpiù o meno lo stesso nella maggior parte dei controller e dei metodi. Non utilizzare un'adeguata funzione di caricamento automatico è una delle cose che non mi piacciono più della compatibilità con le versioni precedenti di CI, ma è tutta un'altra discussione ...
Adam Westbrook,

0

La risposta breve è che la forma dell'esempio di codice è ingannevolmente intuitiva. Sembrerebbe che questa sia una strada "facile per la mente".


Problema n. 1

Il tuo Modele gli Viewoggetti saranno strettamente accoppiati.

Se dovessi mai aggiungere o rimuovere metodi in Model, potresti dover modificare di Viewconseguenza.

Fondamentalmente, MVC è derivato dai modelli Command e Observer . Volete un "Modello" indipendente che viene manipolato tramite un'interfaccia / API che Controllerpuò essere agganciata (ovvero una delega).

Spesso ciò significa iniettare Model e Viewistanze in a Controllere memorizzarle come proprietà di detto Controller. Quindi, usando un metodo del Controller(cioè un comando) come area di lavoro, passare i dati a un View dal Model ( dopo che il `Modello ha terminato l'aggiornamento dello stato dell'applicazione ).

Dati che passano (array, oggetti iterabili, altro) continua a accoppiamento tra Modele Viewistanze sciolto . Se si inietta l' Modelistanza in View, vedere il Problema n. 1 sopra.

Ricorda, Viewspotrebbe essere HTML, JSON, Text, XML, intestazioni HTTP, YAML o quasi qualsiasi cosa, seguendo una metodologia di trasferimento dello stato di rappresentazione (REST) .

Quindi, la chiave per capire come gestire la relazione tra Modele Viewsè vedere la relazione per quello che è, uno-a-molti (potenzialmente)! Questo è esattamente ciò che il modello Observer è stato progettato per realizzare.

Mentre la maggior parte delle configurazioni ha una sola vista di cui occuparsi alla volta, non c'è nulla che impedisca al modello architettonico MVC di aggiornare più viste contemporaneamente! Lavorare con le applicazioni Web CRUD tradizionali fa sì che le persone pensino in un modo uno-a-uno , ma questo è il più piccolo esempio di come il modello Observer potrebbe funzionare ( uno-a-molti è l'altro ).

Pertanto, se ne avessi uno Modele più Views, il potenziale mal di testa dell'aggiornamento di tutto il Views'codice di implementazione perché hai cambiato qualcosa Model'snell'API / metodi ora diventa acuto .

Passare i dati a Views , non istanze di Models .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.