2009-03-02 5 views
9

Sono relativamente nuovo alla programmazione orientata agli oggetti. Capisco praticamente i concetti, ma in pratica sto facendo davvero fatica a trovare informazioni su come utilizzare al meglio i modelli nelle mie applicazioni Zend Framework.Zend Framework: utilizzo di modelli e viste, best practice

In particolare, ho un modello (che non estende nulla) che non utilizza una tabella di database. Usa getter e setter per accedere ai suoi membri protetti. Mi trovo alle prese con il modo migliore per visualizzare questo modello nella vista. Non voglio che la logica nei miei modelli di vista, ma mi trovo nella seguente situazione:

Nel mio controller:

$object = new Object(); 
$object->setName('Foo Bar'); 
$this->view->object = $object; 

A mio modello di vista:

<h2><?= $this->object->getName() ?></h2> 

I don' Mi piace molto chiamare le funzioni nei miei modelli di visualizzazione ma non conosco un modo migliore per farlo. Non voglio che i membri del mio modello da pubblico, ma io fondamentalmente voglio ottenere gli stessi risultati:

<h2><?= $this->object->name ?></h2> 

io non voglio che il mio controller per fare tutto il lavoro di dover conoscere tutto ciò che riguarda il modello:

$object = new Object(); 
$object->setName('Foo Bar'); 
$this->view->object = $object; 
$this->view->object->name = $object->getName(); 

Qual è la migliore pratica di utilizzo dei modelli in Zend Framework? Qualcuno può consigliare qualche tutorial che mi aiuti a capire questo dilemma Modello/Vista in Zend Framework?

risposta

4

Una possibilità è utilizzare i metodi magic __set e __get in PHP.Io li uso in questo modo nel mio classe astratta Modello:

abstract class Model_Abstract 
{ 
    protected $_data; 

    // Private Data Members assigned to protected $_data 
    public function __construct($data = null) 
    { 
     // Makes it so that I can pass in an associative array as well as 
     // an StdObject. 
     if(!is_object($data)) { 
      $data = (object) $data; 
     } 

     $this->_data = $data; 

    } 

    public function __get($key) 
    { 
     if (method_exists($this, '_get' . ucfirst($key))) { 
      $method = '_get' . ucfirst($key); 
      return $this->$method();    
     } 
     else { 
      return $this->_data->$key; 
     } 
    } 

    public function __set($key, $val) 
    { 
     if (method_exists($this, '_set' . ucfirst($key))) { 
      $method = '_set' . ucfirst($key); 
      return $this->$method($val);    
     } 
     else { 
      $this->_data->$key = $val; 
      return $this->_data->$key; 
     } 
    } 
} 


class Model_User extends Model_Abstract 
{ 
    //Example overriding method for the property firstName in the $_data collection. 
    protected function _getFirstName() 
    { 
     // Do some special processing and then output the first name. 
    } 
} 

Questo fa in modo che è possibile specificare getter e setter per le proprietà come necessario, ma fa in modo che non c'è bisogno di definire le funzioni boilerplate per ogni proprietà , solo quelli in cui si desidera eseguire una sorta di elaborazione su di esso prima di restituire il valore. Ad esempio, utilizzo la funzionalità in diversi punti per modificare le date conformi ISO (memorizzate in MySQL) in un formato più compatto e leggibile per gli utenti.

Per quanto riguarda il posizionamento nel controller, è consigliabile consultare this post per ottenere un feedback specifico su come gestire il posizionamento all'interno del controller.

Alcuni pensano che preferirebbero avere un aiutante che carica automaticamente i modelli nella vista e gira del tutto il controller. Personalmente direi che, nel contesto di Zend Framework e PHP, ha molto senso passare i modelli nella vista dal controller perché lo stato dei modelli nella vista dipende spesso da ciò che proviene dalla richiesta (che dovrebbe essere gestita nel controller).

Aggiornamento: Come per le critiche nei commenti, una cosa che vorrei sottolineare è che il livello di accesso al database e dominio (o modello) strato sono davvero due cose diverse, anche se con l'Active Record che si fondono insieme . Ho chiesto un po 'di tempo indietro allo this question e ho ricevuto alcuni utili commenti su questo argomento. Qualunque cosa tu decida di fare con il modello, ti consigliamo di fornire un'API coerente per tutti gli oggetti del dominio, indipendentemente da dove provengano i dati per il modello.

Suppongo che un vantaggio offerto dalla risposta di Saem sia che offre la possibilità di mappare direttamente valori di ritorno di proprietà/funzione da uno o più oggetti dominio all'oggetto vista. Teoricamente l'utilizzo all'interno della vista si presenta quindi come questo:

// Mapped from Model_User::_data->last_name and Model_User::_data->first_name 
$this->name 
+1

Questo è in realtà un modo scadente di fare le cose. Non solo si dà accesso arbitrario a tutte le proprietà, siano esse che devono essere (non) serializzate a/da un modulo o meno, ma sovraccaricano anche il modello con il concetto di mappatura, che è quello che è stato effettivamente chiesto. – Saem

+0

Inserire la logica del modulo nel modello unisce la vista e il modello che è anche una forma scadente. E come ho già detto, ignorare il comportamento di default è molto semplice ed evita la necessità di creare getter e setter stupidi. –

+0

E se osservi la classe Zend_Db_Table_Row, scoprirai che Zend utilizza effettivamente un principio simile per esporre i campi e i relativi valori dalle tabelle. –

3

Se solo altri sviluppatori lavoreranno con i modelli, consiglierei di passare i modelli. Ecco un collegamento a un post di Jeff Atwood su MVC Understanding Model-View-Controller

3

Questo non è particolarmente orientato verso la struttura di Zend, ma il problema è piuttosto generale, nella mia mente.

Sembra che tu sia sulla strada giusta, invece di cablare il modello alla vista, all'interno del controller. Preferiresti questo astratto, specialmente se stai mappando una tonnellata di modelli o mappando lo stesso modello più e più volte.

Qualcosa di semplice sarebbe scrivere un sacco di funzioni di mappatura, il che andrebbe bene se tutto quello che evitavate stesse mappando la stessa cosa più e più volte.

Se si desidera una soluzione più generale, che sia stata anche risolta evitando di scrivere il codice della piastra della caldaia e mantenendo le cose più ASCIUTTE, suggerisco di creare una classe mapper.

È possibile creare un ViewModelMapper, che accetta un modello o alcuni modelli e li associa alla vista.

class ViewModelMapper 
{ 
    public function __construct($view) 
    { 
     //set the properties 
    } 

    public function addModel($model, $overrideViewProperty = null) 
    { 
     //add the model to the list of models to map, use the view's property 
     // name to figure out what to map it to? Allow for an override just in case. 
    } 

    public function getMappedView() 
    { 
     //take the view, map all the models 
    } 
} 

Si potrebbe quindi esempio questo sul controller, e la configurazione delle mappature, quindi il controllore controlla la mappatura ancora, ma tutto il piatto della caldaia e la logica di codifica è centralizzata, per tutte le mappe del controller, tranne rare eccezioni .

+0

Fornire un esempio pertinente che utilizza questa classe Mapper. A partire da ora tutto quello che vedo è un modo per rendere più complessa l'aggiunta di modelli alla vista. –

1

Per una buona lettura sul modello di architettura, read this post. Non parla specificamente della vista, ma vale sicuramente la pena leggerla.

Ho finito per aggiungere una funzione getViewClass() ai miei modelli. Il controller chiama questa funzione per ottenere le variabili protette a cui altrimenti non avrebbe accesso, e la vista non deve preoccuparsi di chiamare qualsiasi getter.

//controller 
$object = new Object(); 
$object->setName('Foo Bar'); 
$this->view->object = $object->getViewClass(); 

//view template 
<h2><?= $this->object->name ?></h2> 

Non so se c'è un modo migliore per ottenere il lavoro fatto in Zend Framework, ma questa è una soluzione.