2009-03-02 7 views
9

Je suis relativement nouveau dans la programmation orientée objet. Je comprends à peu près les concepts, mais pratiquement, j'ai du mal à trouver des informations sur la meilleure utilisation de Models dans mes applications Zend Framework.Zend Framework: Utilisation de modèles et de vues, bonnes pratiques

Plus précisément, j'ai un modèle (qui ne s'étend rien) qui n'utilise pas une table de base de données. Il utilise des getters et setters pour accéder à ses membres protégés. Je me bats avec la meilleure façon d'afficher ce modèle dans la vue. Je ne veux pas logique dans mes modèles de vue, mais je me trouve dans la situation suivante:

Dans mon contrôleur:

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

Dans mon modèle de vue:

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

Je ne J'aime vraiment appeler des fonctions dans mes modèles de vue, mais je ne connais pas de meilleure façon de le faire. Je ne veux pas que mes membres de modèle soient publiques, mais je veux essentiellement à obtenir les mêmes résultats:

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

Je ne veux pas que mon contrôleur pour faire tout le travail d'avoir à tout savoir sur le modèle:

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

Quelle est la meilleure pratique pour utiliser des modèles dans Zend Framework? Quelqu'un peut-il recommander un tutoriel qui m'aiderait à comprendre ce dilemme Model/View dans Zend Framework?

Répondre

4

Une possibilité est d'utiliser les méthodes magic __set et __get en PHP.Je les utilise comme tant dans mon modèle abstrait classe:

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. 
    } 
} 

Ce qu'il fait en sorte que vous pouvez spécifier des accesseurs pour les propriétés que nécessaire, mais fait en sorte que vous ne disposez pas de définir des fonctions de boilerplate pour chaque propriété , juste ceux où vous voulez faire un traitement avant de retourner la valeur. Par exemple, j'utilise la fonctionnalité dans un certain nombre d'endroits pour modifier les dates conformes à l'ISO (telles que stockées dans MySQL) dans un format plus compact et plus lisible pour les utilisateurs.

En ce qui concerne ce qu'il faut placer dans votre contrôleur, je vous recommande de regarder this post pour des commentaires spécifiques sur la manipulation à placer dans votre contrôleur. Certains pensent qu'ils préfèreraient avoir un assistant qui charge automatiquement les modèles dans la vue et contourne complètement le contrôleur. Personnellement, je dirais que dans le contexte de Zend Framework et de PHP, il est très logique de passer des modèles dans la vue depuis le contrôleur car l'état des modèles dans la vue dépend souvent de ce qui vient de la requête dans le contrôleur). Selon les critiques dans les commentaires, une chose que je voudrais souligner est que votre couche d'accès à la base de données et la couche de domaine (ou modèle) sont vraiment deux choses différentes, mais avec l'enregistrement actif, ils sont mélangés ensemble . J'ai demandé this question il y a quelque temps et j'ai reçu des commentaires utiles à ce sujet. Quoi que vous décidiez de faire avec le modèle, vous souhaiterez fournir une API cohérente pour tous les objets du domaine, indépendamment de l'origine des données du modèle.

Je suppose que l'un des avantages offerts par la réponse de Saem est qu'il offre la possibilité de mapper directement les propriétés/les valeurs de retour de fonction d'un ou plusieurs objets de domaine à l'objet de vue. En théorie, l'utilisation dans la vue ressemble alors à ceci:

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

C'est en fait une mauvaise façon de faire les choses. Non seulement vous donnez un accès arbitraire à toutes les propriétés, qu'il s'agisse de celles qui doivent être sérialisées ou non à partir d'un formulaire, mais cela surcharge également le modèle avec le concept de mappage, ce qui a été demandé. – Saem

+0

La mise en forme de la logique dans le modèle mélange la vue et le modèle, qui est également de mauvaise qualité. Et comme je l'ai déjà dit, remplacer le comportement par défaut est très simple et évite la nécessité de créer des getters et setters stupides. –

+0

Et si vous regardez la classe Zend_Db_Table_Row, vous verrez que Zend utilise un principe similaire pour exposer les champs et leurs valeurs à partir des tables. –

3

Si seulement d'autres développeurs vont travailler avec les templates, je recommanderais simplement de passer dans les modèles. Voici un lien vers un post de Jeff Atwood sur MVC Understanding Model-View-Controller

3

Ceci n'est pas particulièrement orienté vers le framework zend, mais le problème est plutôt général, dans mon esprit.

Il semble que vous soyez sur la bonne voie, au lieu de câbler le modèle à la vue, à l'intérieur du contrôleur. Vous préférez avoir ce résumé, particulièrement important si vous cartographiez une tonne de modèles, ou cartographiez le même modèle encore et encore. Quelque chose de simple serait d'écrire un tas de fonctions de mappage, ce qui serait bien si tout ce que vous évitiez est de cartographier la même chose encore et encore.

Si vous vouliez une solution plus générale, qui évitait aussi d'écrire le code de la chaudière et de garder les choses plus au sec, je suggère de créer une classe de mappeur.

Vous pouvez créer un ViewModelMapper, qui prendrait un modèle, ou quelques modèles et les mapper à la vue.

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 
    } 
} 

Vous pouvez ensuite exemple ceci sur votre contrôleur, et configurer les applications, de sorte que le contrôleur commande la mise en correspondance toujours, mais toute la plaque de la chaudière et la logique de codage est centralisée, pour toutes les cartes de contrôleur, à l'exception des rares exceptions .

+0

Veuillez fournir un exemple pertinent utilisant cette classe Mapper. En ce moment tout ce que je vois est un moyen de rendre les modèles à la vue plus complexe. –

1

Pour une bonne lecture sur l'architecture du modèle, read this post. Il ne parle pas spécifiquement de la vue, mais cela vaut vraiment la peine d'être lu.

J'ai fini par ajouter une fonction getViewClass() à mes modèles. Le contrôleur appelle cette fonction pour obtenir les variables protégées auxquelles il n'aurait pas accès autrement, et la vue n'a pas à s'inquiéter d'appeler des getters. Je ne sais pas s'il existe une meilleure façon de faire le travail dans Zend Framework, mais c'est une solution.

Questions connexes